Python 2.4中yield在带finally的try块中不允许的解决方法

4 投票
2 回答
3838 浏览
提问于 2025-04-15 19:45

我现在在用python2.4,所以不能在生成器或者yield中使用finally语句。有没有什么办法可以解决这个问题呢?

我找不到关于如何绕过python 2.4这个限制的资料,而且我想到的一些解决办法(主要是用__del__,并试图确保它在合理的时间内运行)也不是很吸引人。

2 个回答

3

当一个生成器实例被简单地放弃(也就是被垃圾回收)时,唯一能保证被调用的代码是它的局部变量的 __del__ 方法(如果在外面没有对这些对象的引用)和对它的局部变量的弱引用的回调(同样的道理)。我建议使用弱引用的方法,因为它不会干扰其他代码(你不需要一个特别的类来使用 __del__,只要是可以被弱引用的对象就行)。例如:

import weakref

def gen():
  x = set()
  def finis(*_):
    print 'finis!'
  y = weakref.ref(x, finis)
  for i in range(99):
    yield i

for i in gen():
  if i>5: break

这段代码确实会打印出 finis!,正如我们所希望的那样。

7

你可以复制代码来避免使用finally块:

try:
  yield 42
finally:
  do_something()

变成:

try:
  yield 42
except:  # bare except, catches *anything*
  do_something()
  raise  # re-raise same exception
do_something()

(我没有在Python 2.4上试过,你可能需要查看sys.exc_info,而不是上面提到的重新抛出语句,像这样raise sys.exc_info[0], sys.exc_info[1], sys.exc_info[2]。)

撰写回答