except-clause删除局部变量

时间:2014-06-17 19:21:10

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

exc = None
try:
    raise Exception
except Exception as exc:
    pass

# ...

print(exc)
  

NameError:name' exc'未定义

这曾经在Python2中工作。为什么这样改变了?如果我至少可以重新分配给exc,则类似于类级属性

class Foo(object):
    Bar = Bar

但是这也没有成功:

exc = None
try:
    raise Exception
except Exception as exc:
    exc = exc

有什么好的提示可以实现同样的目标吗?我不想写这样的东西:

exc = None
try:
    raise Exception("foo")
except Exception as e:
    exc = e

# ...

print(exc)

1 个答案:

答案 0 :(得分:7)

try语句明确限制了绑定异常的范围,以防止导致其泄漏的循环引用。请参阅try statement documentation

  

当使用as作为目标分配例外时,会在except子句的末尾清除它。

     

[...]

     

这意味着必须将异常分配给其他名称才能在except子句之后引用它。异常被清除,因为附加了回溯,它们与堆栈帧形成一个引用循环,使该帧中的所有本地生存,直到下一次垃圾收集发生。

强调我的;请注意, only选项是将异常绑定到新名称。

在Python 2中,异常没有对回溯的引用,这就是为什么改变它的原因。

但是,即使在Python 2中,也明确警告您要清理回溯,请参阅sys.exc_info()

  

警告:将 traceback 返回值分配给处理异常的函数中的局部变量将导致循环引用。这将阻止同一函数中的局部变量或回溯引用的任何内容被垃圾回收。由于大多数函数不需要访问回溯,因此最好的解决方案是使用exctype, value = sys.exc_info()[:2]之类的东西来仅提取异常类型和值。如果确实需要回溯,请确保在使用后删除它(最好使用try ... finally语句)或在本身不处理异常的函数中调用exc_info()

如果确实重新绑定了异常,则可能需要明确清除回溯:

try:
    raise Exception("foo")
except Exception as e:
    exc = e
    exc.__traceback__ = None