I am novice in Python and programming. Generators are a bit too complicated to understand for new programmers. Here's my theory on generator functions in Python:
Any function contains a
yieldstatement will return a generator objectA generator object is a stack contains state
Each time I call
.nextmethod Python extracts the function's state and when it finds another yield statement it'll bind the state again and deletes the prior state:
Example:
[
[state1] # Stack contains states and states contain info about the function
[state2] # State1 will be deleted when python finds the other yield?
]
This is of course might be like the stupidest theory on earth, but forgive me I am just new in the coding word.
My Questions:
What Python internally makes to store the states ?
Does
yieldstatement adds a state to a stack if it exists ?What yield creates internally ? I understand yield creates a generator object, however, I wonder what generator objects contain that makes them work ? are they just a stack/list of states and we you use
.nextmethod to extract each state and Python will call the function with the indexed state automatically for instance ?
This is correct. The return value of a function containing a
yieldis a generator object. The generator object is an iterator, where each iteration returns a value that wasyielded from the code backing the generator.A generator object contains a pointer to a the current execution frame, along with a whole bunch of other stuff used to maintain the state of the generator. The execution frame is what contains the call stack for the code in the generator.
Sort of. When you call
next(gen_object), Python evaluates the current execution frame:PyEval_EvalFrameis highest-level function used to interpret Python bytecode:It knows that when it hits a
yieldwhile evaluating the bytecode, it should return the value being yielded to the caller:When you yield, the current value of the frame's value stack is maintained (via
f->f_stacktop = stack_pointer), so that we can resume where we left off whennextis called again. All non-generator functions setf_stacktoptoNULLafter they're done evaluating. So when you callnextagain on the generator object,PyEval_ExvalFrameExis called again, using the same frame pointer as before. The pointer's state will be exactly the same as it was when it yielded during the previous, so execution will continue on from that point. Essentially the current state of the frame is "frozen". This is described in the PEP that introduced generators:Here is most of the state a generator object maintains (taken directly from its header file):
gi_frameis the pointer to the current execution frame.Note that all of this is CPython implementation-specific. PyPy/Jython/etc. could very well be implementing generators in a completely different way. I encourage you to read through the source for generator objects to learn more about CPython's implementation.