代码之家  ›  专栏  ›  技术社区  ›  abyx

为什么需要显式删除sys.exc_info()跟踪?

  •  12
  • abyx  · 技术社区  · 15 年前

    我看过不同的代码库,只是在pymotw上阅读(见第一条注释 here )。

    解释说,如果追溯被分配给变量,那么将创建一个循环。 sys.exc_info()[2] 但为什么呢?

    这有多大问题?我应该搜索 exc_info 在我的代码库中,确保删除了回溯?

    2 回复  |  直到 7 年前
        1
  •  20
  •   Brandon Rhodes    7 年前

    python 3(更新为原始答案):

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

    Python 2:

    python垃圾收集器最终会找到并删除循环引用,比如从堆栈帧内部引用一个回溯堆栈创建的循环引用,所以不要返回并重写代码。但是,向前看,你可以听从

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

    (在IT文档中 exc_info() 并说:

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

    当你需要抓住例外的时候。

    还有两个想法:

    首先,你为什么要跑步 ExcIf() 完全?

    如果你想抓住一个例外,你不应该说:

    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垃圾收集器才能解决这个问题,因为它最终会注意到循环并将其破坏。

    因此理解这种情况的关键是“回溯”对象第三件事(在索引2处)返回 ExcIf() _包含调用异常时激活的每个函数的“堆栈帧”。这些堆栈帧是 “死亡”物体显示什么 当调用execption时为true;帧仍处于活动状态!捕获异常的函数仍然是活动的,因此其堆栈框架是活动的,在代码执行以处理异常时,变量引用仍在增长和丢失(在完成“except”子句并继续工作时,执行其他任何操作)。

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

        2
  •  11
  •   Alex Martelli    15 年前

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

    尤其是在长时间运行的程序中,干扰垃圾收集不是最好的主意,因为您将保留不真正需要的内存(时间比需要的时间长,或者如果通过让这些循环包含带有终结器的对象而基本上阻止了垃圾收集,则可以无限期地保留)。

    所以,最好尽快消除回溯,不管它们是否来自 exc_info 或不是!