【问题标题】:try-finally in Python 3 generatorPython 3 生成器中的 try-finally
【发布时间】:2019-05-10 00:27:19
【问题描述】:

我遇到了一个 Python 3 代码的 sn-p:

def gen():
    try:
        while True:
            yield 1
    finally:
        print("stop")

print(next(gen()))

我运行之后,一开始以为输出应该是:

1

但实际上结果是:

stop
1

怎么会这样?幕后发生了什么?

如果我运行for i in gen(): print(i),将会出现我所期望的无限循环。 for 和 next 这里有什么区别?

【问题讨论】:

  • 你在什么环境下运行这个?
  • @VinceW。 python3.6.5
  • 得到它,发布一个答案,关于垃圾收集
  • 相关的line from the documentation:“yield 表达式允许在 try 构造中的任何位置。如果生成器在最终确定之前没有恢复(通过达到零引用计数或被垃圾收集),则将调用生成器迭代器的 close() 方法,允许执行任何未决的 finally 子句。"

标签: python python-3.x generator try-except


【解决方案1】:

finally 子句正在对生成器对象的垃圾回收执行。

考虑以下两种情况:

def gen():
    try:
        while True:
            yield 1
    finally:
        print("stop")

g1 = gen(); print('first time')
print(next(g1))
g2 = gen(); print('second time')  # no stop will be printed because we haven't hit the finally clause yet
def gen():
    try:
        while True:
            yield 1
    finally:
        print("stop")

g = gen(); print('first time')
print(next(g))
g = gen(); print('second time')   # stop will be printed when the first object g was assigned to is garbage collected

【讨论】:

  • 我认为你的观点是正确的。但是您的示例代码仅在交互式解释器中显示正确的结果。
  • 不确定您在做什么,但我只是将两个文本块放入一个文件并运行它们。实际上,我本来希望看到两个stops 在这两种情况下都打印出来,因为我本来希望有两个对象被垃圾回收,但我在这两种情况下都只看到一个。感觉像是另一个问题在解决中......
  • 再说一次,我不确定我明白你在做什么,但现在我明白我对我的评论的困惑了。在调用下一个方法之前,永远不会进入 try 块。所以当 g1 和 g2 都被垃圾回收时,只有 g1 进入了 try 块,所以退出时会调用 finally 语句,而 g2 还没有进入 try 块
【解决方案2】:

当生成器关闭时循环终止,如果你不保存对它的引用,这会自动发生。一旦发生这种情况,try 语句保证在生成器对象被垃圾回收之前执行finally 块。比较:

>>> next(gen())
stop
1

与

>>> x = gen()
>>> next(x)
1

【讨论】:

    猜你喜欢
    • 2012-01-24
    • 2018-03-19
    • 2016-12-05
    • 2014-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-31
    • 1970-01-01
    相关资源
    最近更新 更多