Reputation: 1927
I am trying to yield
a context manager that is created in a with
statement. However, something that I don't understand happens: the context manager is closed before it is yielded, even though the execution in the generator did not exit the scope of the with
. For example:
class CM:
def __enter__(self):
print('enter cm')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('exit cm')
def make_foo():
with CM() as cm:
print('before yield')
yield cm
print('after yield')
print('before make_foo')
foo = next(make_foo())
print('after make_foo')
outputs
before make_foo
enter cm
before yield
exit cm
after make_foo
I saw this thread on a related topic, and the answer is about time when the object is garbage collected -- however why would cm
be garbage collected before it is returned to be used by the caller here?
EDIT
When writing instead
foo_maker = make_foo()
foo = next(foo_maker)
then the CM is not closed -- so it seems that the CM is indeed GC because the generator is GC. But shouldn't it left alone since it is returned and potentially used after?
Upvotes: 1
Views: 625
Reputation: 370
I think this is because of your method definition and how you call it.
if you instead of foo = next(make_foo())
use this :
for i in make_foo():
print('thanks I saw cm')
the result would be this :
enter cm
before yield
thanks I saw cm
exit cm
after yield
after make_foo
Upvotes: 1