我已经在不同的代码库中看到了,只是在PyMOTW上阅读(参见这里的第一个注释).
解释说,如果将回溯分配给变量sys.exc_info()[2],将创建一个循环,但为什么呢?
这有多大的问题?我应该exc_info在我的代码库中搜索所有用法并确保删除回溯吗?
Bra*_*des 20
Python 3(更新到原始答案):
在Python 3中,问题中引用的建议已从Python文档中删除.我的原始答案(以下)仅适用于在其文档中包含引用的Python版本.
Python 2:
Python垃圾收集器最终将查找和删除循环引用,如通过从其中一个堆栈框架内部引用回溯堆栈而创建的循环引用,因此不要返回并重写代码.但是,展望未来,你可以遵循建议
http://docs.python.org/library/sys.html
(在哪里记录exc_info())并说:
exctype, value = sys.exc_info()[:2]
Run Code Online (Sandbox Code Playgroud)
当你需要抓住异常时.
还有两个想法:
首先,你为什么要跑步exc_info()?
如果你想捕捉异常,你不应该只说:
try:
...
except Exception as e: # or "Exception, e" in old Pythons
... do with with e ...
Run Code Online (Sandbox Code Playgroud)
而不是sys模块化模块内的对象?
第二:好的,我已经给出了很多建议,但没有真正回答你的问题.:-)
为什么要创建一个循环?好吧,在简单的情况下,当对象引用自身时会创建一个循环:
a = [1,2,3]
a.append(a)
Run Code Online (Sandbox Code Playgroud)
或者当两个对象相互引用时:
a = [1,2,3]
b = [4,5,a]
a.append(b)
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,当函数结束时,变量值仍然存在,因为它们被锁定在引用计数容器中:两者都不会消失,直到另一个先消失!只有现代的Python垃圾收集器才能通过最终注意到循环并打破它来解决这个问题.
因此理解这种情况的关键是"追溯"对象 - 第三件事(在索引#2处)返回exc_info()- 包含一个"堆栈帧",用于调用异常时处于活动状态的每个函数.那些堆栈帧不是 "死"对象,表明在调用execption时它是真的; 帧仍然活着!捕获异常的函数仍然存在,因此它的堆栈框架是一个生物,仍然在增长和丢失变量引用,因为它的代码执行来处理异常(并且在完成"except"子句时执行其他任何操作关于它的工作).
所以当你说t = sys.exc_info()[2],回溯中的其中一个堆栈框架 - 实际上属于当前正在运行的函数的框架 - 现在有一个名为的变量t指向堆栈框架本身,创建一个循环就像我上面展示的那些.
Ale*_*lli 11
回溯包含对所有活动帧的引用,这些活动帧又包含对那些不同帧中所有局部变量的引用 - 这些引用是回溯和帧对象的重要部分,因此这并不令人惊讶.因此,如果你将一个引用添加回traceback(或者在临时添加它时未能及时删除它),你就不可避免地形成一个大的引用循环 - 这会干扰垃圾收集(如果任何一个对象可能会完全阻止它)在循环中属于覆盖的类,__del__终结器方法).
特别是在一个长期运行的程序中,干扰垃圾收集并不是最好的想法,因为你将持有你并不真正需要的内存(超过必要的时间,或者如果你基本上阻止垃圾收集则无限期)通过让它们包含具有终结器的对象来实现这样的循环.
因此,无论它们是否来自,最好尽快摆脱追溯exc_info!