Python 是不是;“收益率”-如果在“内部”中执行,则触发“退出”功能;加上;块
从带有块的Python 是不是;“收益率”-如果在“内部”中执行,则触发“退出”功能;加上;块,python,Python,从带有块的内部,但是屈服如何 如果下一次调用函数,块的\uuuuu exit\uuu是否在yield上被调用,然后\uuuu enter\uuu是否再次被调用?还是等待生成器退出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.
内部,但是屈服如何
如果下一次调用函数,块的\uuuuu exit\uuu
是否在yield
上被调用,然后\uuuu enter\uuu
是否再次被调用?还是等待生成器退出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)
收益
在中使用
插入不会触发\uuuu退出
。发电机内部的控制流必须离开带有
的块,才能触发\uuuuuuu退出
;挂起生成器不算作将与
块分开。这在精神上类似于上下文切换到另一个线程也不会触发\uuuuuuuuuuu
。让我们进行经验测试
class MyContextManager:
def __enter__(self):
pass
def __exit__(self, *args):
print "Context manager is exiting."
def f():
print("Entered Function.")
with MyContextManager() as m:
print("Entered with statement. Yielding...")
yield m
print("Yielded. About to exit with statement.")
print("Now outside of with statement.")
for x in f():
pass
输出:
C:\Users\Kevin\Desktop>test.py
Entered Function.
Entered with statement. Yielding...
Yielded. About to exit with statement.
Context manager is exiting.
Now outside of with statement.
“上下文管理器正在退出”消息出现在“即将使用语句退出”消息之后,因此我们可以得出结论,yield
语句不会触发\uuuuuuu退出
方法。简言之:否,它将在到达yield
语句时暂停该方法。如果您请求下一个元素,则会执行剩余部分
如果你写了result=tmp\u csv\u file()
什么都没做:所以甚至没有执行tmp\u path='tmp.csv'
现在,如果调用next(result)
,Python将开始计算函数,直到它到达第一个yield
语句。因此,它执行tmp\u path='tmp.csv'
,打开(…)
s文件并进入环境。它点击yield
语句,从而返回csv\u文件
。现在,您可以对该文件执行任何操作。文件将保持打开状态(只要您不显式地关闭()
),并且\uuuuuuu\uuuuu
将不被调用
但是,如果您第二次调用next(result)
a,Python将继续寻找下一个yield
语句。因此,它将退出环境中的,并删除文件(os.remove(tmp\u路径)
)。然后它到达方法的结尾。这意味着我们完成了。因此,next(…)
将抛出一个错误,表示iterable已用尽。这取决于:
- 如果您的生成器函数超出范围(或被删除),则调用
\uuu退出\uuu
- 如果发电机耗尽,则调用
\uuuu退出
=>只要生成器在with块中且未耗尽,并且保存生成器的变量未被删除,则不会调用\uuuuu exit\uuuu
例如:
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
测试它:
>>> 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
或者,如果手动删除:
>>> a = funfunc()
>>> next(a)
init
enter
1
>>> del a # exit because the variable holding the suspended generator is deleted.
exit
我会假设,发电机不会拯救他们在那个时候屈服的状态,这样他们就可以从那个点继续下去。您不使用内置的有什么原因吗?您不能自己测试一下吗(因为您显然也没有花时间阅读文档)?注意:“with”块称为上下文管理器:@暂时的狼我不知道它的存在,谢谢你的提示@马蒂诺当然可以,也一定会,不过我在上面贴了一篇文章,让其他人也能找到答案。此外,MSeifert的回答揭示了一些我不想测试的问题,因此在这里提问确实有回报:)接受了这一点,因为添加了关于删除和范围的信息,使其更完整。您不必耗尽生成器,只需使用
将其从中推进即可。至于删除它,生成器在垃圾收集时是close
d,但这并不总是立即发生或根本不会发生(尤其是在CPython以外的任何情况下),而且即使在close
d时,有缺陷的生成器也可能不会退出。@user2357112但耗尽是一种可能性(因为它相当于一个返回None
)-即使上下文管理器没有立即退出,它最终也会在对象被销毁时退出(您是否有证据表明一个实现没有这样做,或者只是一个猜测?)。然而,您的最后一点很有趣:您所说的“错误”是什么意思未使用
?@MSeifert:、finally
块和退出方法退出的生成器可能无法运行。