该行为 没有得到 充分的记录,并且在从1.5到ish _直至 Python 3.4的_所有版本的Python中都存在该行为:
作为此更改的一部分,None
在大多数情况下,在解释器关闭期间不再强制将模块全局设置为设置,而是依靠循环垃圾收集器的正常操作。
该行为的唯一文档是moduleobject.c
源代码:
/* To make the execution order of destructors for global
objects a bit more predictable, we first zap all objects
whose name starts with a single underscore, before we clear
the entire dictionary. We zap them by replacing them with
None, rather than deleting them from the dictionary, to
avoid rehashing the dictionary (to some extent). */
请注意,将值设置None
为最优。另一种选择是从映射中删除名称,这将导致不同的错误(尝试从处理程序中使用全局变量时,将使用NameError
异常而不是AttributeError
s__del__
)。
正如您在邮件列表中发现的那样,此行为早于循环垃圾收集器;它是在1998年添加的,而循环垃圾收集器是在2000年添加的。由于功能对象始终引用模块,因此模块中的__dict__
所有功能对象都包含循环引用,这就是为什么__dict__
在GC发挥作用之前需要进行清除的原因。
即使添加了循环GC,也可以将其保留在原位,因为可能有对象__del__
涉及循环方法。这些在其他方面是不可回收的,清理模块字典至少会__dict__
从此类循环中删除模块。不这样做将使该模块的所有 引用的全局变量保持活动状态。
现在,对PEP442所做的更改使垃圾回收器可以使用提供__del__
终结器的对象清除循环引用,从而在__dict__
大多数情况下 无需清除模块。代码仍然存在,但是仅当该__dict__
属性仍然有效时才触发,即使将其内容sys.modules
移至弱引用并在解释器关闭时启动GC收集运行之后也是如此。模块终结器只需减少其引用计数即可。