如果在“with”块内完成,“yield”-ing 是否会触发 __exit__ 函数?

Jad*_*d S 5 python

这个问题是关于从块内部返回而提出的with,但是屈服怎么样?

__exit__如果下次调用该函数,该块是否会被调用yield,然后__enter__再次被调用?或者它是否等待生成器退出 with 块(或返回)

举个例子 :

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)
Run Code Online (Sandbox Code Playgroud)

MSe*_*ert 4

这取决于:

  • 如果您的生成器函数超出范围(或以其他方式被删除),__exit__则会调用该函数。

  • 如果发电机耗尽,则__exit__调用。

=> 只要生成器位于 with 块中且未耗尽,并且保存生成器的变量未删除,则__exit__不会被调用。

例如:

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
Run Code Online (Sandbox Code Playgroud)

测试它:

>>> 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
Run Code Online (Sandbox Code Playgroud)

或者如果手动删除:

>>> a = funfunc()
>>> next(a)
init
enter
1
>>> del a  # exit because the variable holding the suspended generator is deleted.
exit
Run Code Online (Sandbox Code Playgroud)

  • 您不必“耗尽”生成器,只需将其从“with”中推进即可。至于删除它,生成器在垃圾回收时会“关闭”,但这并不总是立即发生或根本不会发生(尤其是在 CPython 之外的任何东西上),并且有缺陷的生成器即使在“关闭”时也可能不会退出“with” `d。 (2认同)