繁体   English   中英

为什么需要显式删除sys.exc_info()回溯?

[英]Why is there a need to explicitly delete the sys.exc_info() traceback?

我已经在不同的代码库中看到了,只是在PyMOTW上阅读(参见这里的第一个注释)。

解释说,如果将回溯分配给sys.exc_info()[2]的变量,将创建一个循环,但为什么会这样?

这有多大的问题? 我应该在我的代码库中搜索exc_info所有用法并确保删除回溯吗?

Python 3(更新到原始答案):

在Python 3中,问题中引用的建议已从Python文档中删除。 我的原始答案(以下)仅适用于在其文档中包含引用的Python版本。

Python 2:

Python垃圾收集器最终将查找和删除循环引用,如通过从其中一个堆栈框架内部引用回溯堆栈而创建的循环引用,因此不要返回并重写代码。 但是,展望未来,你可以遵循建议

http://docs.python.org/library/sys.html

(它记录了exc_info() )并说:

exctype, value = sys.exc_info()[:2]

当你需要抓住异常时。

还有两个想法:

首先,你为什么要运行exc_info()

如果你想捕捉异常,你不应该只说:

try:
    ...
except Exception as e:  # or "Exception, e" in old Pythons
    ... do with with e ...

而不是与sys模块内的对象混淆?

第二:好的,我已经给出了很多建议,但没有真正回答你的问题。 :-)

为什么要创建一个循环? 好吧,在简单的情况下,当对象引用自身时会创建一个循环:

a = [1,2,3]
a.append(a)

或者当两个对象相互引用时:

a = [1,2,3]
b = [4,5,a]
a.append(b)

在这两种情况下,当函数结束时,变量值仍然存在,因为它们被锁定在引用计数容器中:两者都不会消失,直到另一个先消失! 只有现代的Python垃圾收集器才能通过最终注意到循环并打破它来解决这个问题。

所以理解这种情况的关键是一个“追溯”对象 - 由exc_info()返回的第三个东西(索引#2 exc_info() - 包含一个“堆栈帧”,用于调用异常时处于活动状态的每个函数。 那些堆栈帧不是 “死”对象,表明在调用execption时它真的; 帧仍然活着! 捕获异常的函数仍然存在,因此它的堆栈框架是一个生物,仍然在增长和丢失变量引用,因为它的代码执行来处理异常(并且当它完成“except”子句时执行其他任何操作关于它的工作)。

所以当你说t = sys.exc_info()[2] ,回溯中的一个堆栈帧 - 实际上属于当前正在运行的函数的帧 - 现在有一个名为t的变量回到堆栈框架本身,创建一个循环就像我上面展示的那样。

回溯包含对所有活动帧的引用,这些活动帧又包含对那些不同帧中所有局部变量的引用 - 这些引用是回溯和帧对象的重要部分,因此这并不令人惊讶。 因此,如果你将一个引用添加回traceback(或者在临时添加它时未能及时删除它),你就不可避免地形成一个大的引用循环 - 这会干扰垃圾收集(如果任何一个对象可能会完全阻止它)在循环中属于覆盖__del__类,终结器方法)。

特别是在一个长期运行的程序中,干扰垃圾收集并不是最好的想法,因为你将持有你并不真正需要的内存(超过必要的时间,或者如果你基本上阻止垃圾收集则无限期)通过让它们包含具有终结器的对象来实现这样的循环。

因此,无论是否来自exc_info ,最好尽快摆脱追溯!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM