Calling a function, that yields, twice
Solution 1:
One of my favorite tools to visualize Python with is PythonTutor.
Basically, you can see that on the first run next(pre_worker)
returns the _inner
function. Since _inner
is inside db_connect_n_clean
, it can access all of its variables.
Internally, in Python, _inner
contains a reference to db_connectors
. You can see the reference under __closure__
:
>>> gen = db_connect_n_clean()
>>> inner = next(gen)
>>> inner.__closure__
(<cell at 0x000001B73FE6A3E0: list object at 0x000001B73FE87240>,)
>>> inner.__closure__[0].cell_contents
[]
The name of the reference is the same as the variable:
>>> inner.__code__.co_freevars
('db_connectors',)
Every time this specific function, with this specific __closure__
tries to access the db_connectors
, it goes to the same list.
>>> inner(1)
Connect : 1
>>> inner(2)
Connect : 2
>>> inner.__closure__[0].cell_contents
[1, 2]
The original generator gen()
is still paused at the first yield
:
>>> gen.gi_frame.f_lineno
6 # Gen is stopped at line #6
>>> gen.gi_frame.f_locals["db_connectors"]
[1, 2]
When you advance it again using next()
it continues on from the yield
and closes everything:
>>> next(gen)
Dispose : 1
Dispose : 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
If you wish to understand how do generators work in general, there are plenty of answers and articles on the subject. I wrote this one for example.
If I didn't fully explain the situation, feel free to ask for clarification in the comments!