Question presented to candidate:
"A generator object goes through several states between the moment you call the function and the moment it is gone. Walk me through them. What moves it from one state to the next, and what happens to code in a finally block if the consumer stops early?"
What a strong answer should cover:
- The four states reported by
inspect.getgeneratorstate:GEN_CREATED(body not started),GEN_RUNNING(executing right now),GEN_SUSPENDED(paused at ayield),GEN_CLOSED(finished); a generator never comes back from closed - What moves it:
next()/send(value)resume it (andsendmust beNoneon a just-created generator);yieldsuspends it;returnor an uncaught exception closes it, with the return value carried onStopIteration.value throw(exc)raises an exception at the pausedyield;close()raisesGeneratorExitthere, sofinallyblocks andwithexits run; a generator that yields again afterGeneratorExitgetsRuntimeError- Dropping the last reference to a suspended generator closes it as well (in CPython this happens immediately through reference counting);
breakout of aforloop leaves it suspended, not closed - PEP 479 (default since 3.7): a
StopIterationescaping the body is turned intoRuntimeError; version details such as the three-argumentthrow()being deprecated in 3.12,gi_suspended(3.11) andclose()returning a value (3.13) - Introspection:
gi_frame(None once closed),gi_running,gi_frame.f_locals
Code / implementation expected: Optional โ a generator with a try/finally, printing inspect.getgeneratorstate before, during and after, and calling close().