擅长:python、mysql、java
<p>一般来说,至少在3.4和更高版本中,模块对象在这方面不应该有任何特殊之处。当然,通常情况下,<code>sys.modules</code>中的每个加载模块都有一个引用,但是如果您显式删除了它,那么一个模块应该能够消失。在</p>
<p>尽管如此,过去肯定有一些问题阻止了这种情况的发生,我也不保证在3.7版之后不会有这样的问题。在</p>
<p>不幸的是,你的测试实际上并没有测试任何东西。大概你在用CPython。在CPython中,垃圾回收器使用引用计数,它直接在每个对象上存储一个计数,每次绑定新名称时递增或递减计数,如果计数为0,则立即将其删除。{orelse>在某些情况下,{2>引用两个特殊的对象,其中每个对象都引用cd2}。如果模块不是这样一个循环的一部分,它将在您调用<code>gc.collect()</code>之前被删除,因此它当然会返回0。但0告诉你什么也没有。在</p>
<p>你的测试还有其他问题。在</p>
<p>首先,您不应该在交互式解释器中测试垃圾。各种额外的东西都被放在那里,以一种很难解释的方式。写一个测试脚本要好得多。在</p>
<p>其次,您不应该使用<code>math</code>作为测试。它是一个扩展模块(也就是说,是用C而不是Python编写的),即使在3.5中进行了重大更改之后,它们仍然不能正常工作。它也是一个核心模块,可能是启动的一部分,也可能是解释器的其他部分所需要的,即使您没有从代码中引用它。所以,最好用别的东西。在</p>
<p>不管怎样,我认为有一种方法可以直接测试它,而不使用调试器,但不能保证它是否有效。在</p>
<p>首先,您需要创建<code>types.ModuleType</code>的子类,它有一个<code>__del__</code>方法,可以打印出一些消息。然后,您只需要导入一个模块(一个.py模块,而不是一个扩展模块)并将其<code>__class__</code>设置为该子类。它可能与.py文件中的<code>__class__ = MyModuleSubclass</code>一样简单。现在,当它被收集时,它的析构函数将运行,你将有证据证明它是被收集的。(好吧,证明它是被收集的,除非析构函数恢复了它,但是如果你的析构函数除了打印一个静态字符串之外什么也不做,那就不必担心了。)</p>