Question presented to candidate:
"Python has yield from. Isn't that just a shorter way of writing for x in sub: yield x? Explain what it really does, and when the difference matters."
What a strong answer should cover:
yield from <iterable>makes the current generator a pass-through for a sub-iterator: every value the sub-iterator produces goes straight to the outer caller, and the outer generator stays paused at that line until the sub-iterator is exhausted.- It is more than the
forloop:send()values,throw()exceptions andclose()are forwarded to the subgenerator, which the loop version cannot do (the loop only ever callsnext()). - The value of the
yield fromexpression is the subgenerator'sreturnvalue, carried byStopIteration.valueโ soresult = yield from sub()lets helper generators return results. - Typical uses: flattening recursive structures, splitting a large generator into smaller helper generators, and (historically) the generator-based coroutines that came before
async/await. It was added by PEP 380 in Python 3.3. - CPython details:
GET_YIELD_FROM_ITER+ aSENDloop in the bytecode, andgi_yieldfrompointing at the current delegate;yield fromis aSyntaxErrorinsideasync def.
Code / implementation expected: Optional โ a small delegating generator that captures a subgenerator's return value, or a recursive flatten.