代码1:
def af():
a=65
try:
yield a
finally:
print('end')
print(af().next())
码2:
def af():
a=65
try:
yield a
finally:
print('end')
g=af()
print(g.next())
code1的结果是:
end
65
但是code2的结果是:
65
end
答案 0 :(得分:0)
在代码段1中,当Python执行时
print(af().next())
它通过
af().next()
然后生成器对象的引用计数降为0.此时,Python调用生成器的close
方法来强制finally
块和__exit__
方法运行,因此{{ 1}}块打印finally
。
然后 end
的{{1}}部分会运行并打印print
。
在代码段2中,当Python执行时
print(af().next())
生成器对象通过65
变量的引用保持活动状态,因此此时print(g.next())
块不会运行,并且Python打印g
。
然后,在解释器关闭期间,生成器的引用计数降为0,finally
触发65
块,打印close
。这不能保证会发生 - Python不保证在解释器关闭时活动的对象会调用它们的析构函数 - 但它确实发生了。
答案 1 :(得分:0)
关于发电机本身何时清理的问题。当你没有保存对生成器的引用时,一旦最后一个引用超出范围(至少在CPython上,"引用"解释器,这是适当的,因为它&#39 ; s引用计数),清理生成器,立即在生成器的主体中引发GeneratorExit
,使其到达finally
块并打印。
在您的第一个示例中print(af().next())
返回next
时,不再有任何生成引用,因此它已被清理,导致finally
阻止要立即执行(print
尚未调用,我们仍然会获得传递给它的参数。)
在第二个示例中,您在g
中保存了对生成器的引用,因此在g
被销毁之前(在这种情况下在程序退出时),生成器仍然可以恢复(它将恢复在yield
之后。 print
完成后,程序将结束程序清理并执行finally
块。
请注意,像这样的全局变量的清理是不能保证的; CPython 2.7碰巧在关机时将所有全局变量设置为None
,这会让你产生这种行为,但它不是契约性的;您希望明确地用完或close
生成器(如果需要,可以通过contextlib.closing
),以确保它真正得到清理。