gpt4 book ai didi

python - 未使用的生成器中的上下文管理器是如何完成的?

转载 作者:太空狗 更新时间:2023-10-30 01:36:04 26 4
gpt4 key购买 nike

我不明白未完成生成器中的上下文管理器如何以及何时关闭。考虑以下上下文管理器和函数:

from contextlib import contextmanager

@contextmanager
def ctx():
print('enter ctx')
yield
print('exit ctx')

def gen_nums(n):
with ctx():
yield from range(n)

我的第一个直觉是,如果我调用 gen_nums 但没有完全使用生成器,ctx 将永远不会关闭,这是相当令人担忧的。例如:

for i, j in zip(range(5), gen_nums(10)):
print(f'{i}, {j}')

这里 exit ctx 不是在最后打印的。如我所见,这意味着如果我在生成器中有一个文件上下文,它将保持打开状态;但是我随后意识到对文件执行相同操作实际上会正确关闭文件。经过一些测试,我发现如果我这样做:

from contextlib import contextmanager

@contextmanager
def ctx():
print('enter ctx')
try:
yield
finally:
print('exit ctx')

现在 exit ctx 被打印在最后。所以我想在某个时候会触发一些异常,但我不知道是哪个、何时何地(我试图用 except BaseException as e 打印异常,但它没有用)。删除生成器时似乎会发生这种情况,因为如果我这样做:

g = gen_nums(10)
for i, j in zip(range(5), g):
print(f'{i}, {j}')
del g

然后 exit ctx 只发生在 del g 之后。但是,我想更好地了解这里发生的事情以及谁触发了什么。

最佳答案

考虑一下:

@contextmanager
def ctx():
print('enter ctx')
try:
print('ctx begins yield')
yield
print('ctx finishes yield')
finally:
print('exit ctx')

def gen_nums(n):
print('entering generator')
l = range(n)
with ctx():
print('inside context manager')
for i in l:
print('gen before yield')
yield i
print('gen after yield')
print('existing ctx')
print('exiting generator')

结果是:

>>> g = gen_nums(3)
>>> next(g)
entering generator
enter ctx
ctx begins yield
inside context manager
gen before yield
0
>>> next(g)
gen after yield
gen before yield
1
>>> next(g)
gen after yield
gen before yield
2
>>> next(g)
gen after yield
exiting ctx
ctx finishes yield
exit ctx
exiting generator
Traceback (most recent call last):
File "<pyshell#165>", line 1, in <module>
next(g)
StopIteration

contextmanager 似乎只在生成器 的最后一次迭代之后 和它命中 之前真正退出>停止迭代。所以在 generator 的最后一次迭代中,如果 contextmanager 没有在 for 循环中运行(它处理 StopIteration ).

您将无法在 contextmanager 中捕获 StopIteration,因为它发生在 generator 之后> 已耗尽,此时 contextmanager 已经退出。

此外,IIRC,在构建 contextmanager 时,您应该始终使用 try...finally... 无论如何。

关于python - 未使用的生成器中的上下文管理器是如何完成的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54240640/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com