This question as been asked with respect to returning from inside the with
block, but how about yielding?
Does the block's __exit__
get called on yield
and then __enter__
gets called again if the function is next invoked? Or does it wait for the generator to exit the with block (or to return)
as an example :
def tmp_csv_file():
tmp_path = 'tmp.csv'
with open(tmp_path, 'w+') as csv_file:
yield csv_file # will this close the file?
os.remove(tmp_path)
It depends:
If your generator function goes out of scope (or is otherwise deleted) the __exit__
is called.
If the generator is exhausted the __exit__
is called.
=> As long as the generator is in the with-block and not-exhausted and the variable holding the generator is not deleted the __exit__
is not called.
For example:
class Test(object):
def __init__(self):
print('init')
def __enter__(self):
print('enter')
def __exit__(self, *args, **kwargs):
print('exit')
def funfunc():
with Test():
yield 1
yield 2
Testing it:
>>> a = funfunc()
>>> next(a) # no exit
init
enter
1
>>> next(a) # no exit
2
>>> next(a, 0) # exit because generator leaves the with-context inside the function
exit
0
Or if manually deleted:
>>> a = funfunc()
>>> next(a)
init
enter
1
>>> del a # exit because the variable holding the suspended generator is deleted.
exit
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With