CPython 有一个奇怪的行为,它在关闭期间将模块设置为 None。这会在我编写的一些多线程代码关闭期间搞砸错误记录。
我找不到有关此行为的任何文档。 PEP 432 中顺便提到过:
[...] significantly reducing the number of modules that will experience the "module globals set to None" behaviour that is used to deliberate break cycles and attempt to releases more external resources cleanly.
有SO questions about this behaviour和 C API documentation mentions shutdown behaviour for embedded interpreters .
我还找到了 related thread on python-dev和 related CPython bug :
This patch does not change the behavior of module objects clearing their globals dictionary as soon as they are deallocated.
这种行为记录在哪里?它是特定于 Python 2 的吗?
最佳答案
这种行为没有有很好的记录,并且存在于从大约 1.5-ish 到 Python 3.4 的所有 Python 版本中:
As part of this change, module globals are no longer forcibly set to
None
during interpreter shutdown in most cases, instead relying on the normal operation of the cyclic garbage collector.
该行为的唯一文档是 moduleobject.c
source code :
/* 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
在尝试使用来自 __del__< 的全局变量时
处理程序)。
正如您在邮件列表中发现的那样,这种行为早于循环垃圾收集器;它是 added in 1998 ,而循环垃圾收集器是 added in 2000 .由于函数对象总是引用模块 __dict__
模块中的所有函数对象都涉及循环引用,这就是 __dict__
需要在 GC 发挥作用之前清除的原因。
即使添加了循环 GC,它也会保留在原地,因为循环中可能存在具有 __del__
方法的对象。这些aren't otherwise garbage-collectable ,并且清除模块字典至少会从此类循环中删除模块 __dict__
。不这样做将使该模块的所有引用的全局变量保持事件状态。
对 PEP 442 所做的更改现在,垃圾收集器可以使用提供 __del__
终结器的对象清除循环引用,从而无需清除模块 __dict__
在大多数情况下时间>。代码是still there但这只有在 __dict__
属性仍然存在时才会触发,即使在将 sys.modules
的内容移动到弱引用并在解释器关闭时启动 GC 收集运行之后;模块终结器只是减少它们的引用计数。
关于python - Python 的关闭过程设置模块全局变量在哪里记录?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25649676/