Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does "yield"-ing trigger the __exit__ function if done inside a "with" block?

Tags:

python

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)
like image 276
Jad S Avatar asked Jan 04 '23 12:01

Jad S


1 Answers

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
like image 166
MSeifert Avatar answered Jan 27 '23 08:01

MSeifert