一直是SO的长期浏览器,最后问我自己的问题!
所以,我正在编写一个自动化脚本/模块,它以递归方式查找具有特定名称的python模块的目录。如果我找到一个具有该名称的模块,我会动态加载它,从中获取我需要的内容,然后将其卸载。我注意到,虽然简单地对模块进行了删除并没有删除对该模块的所有引用,但是在某个地方还有另一个延迟,我不知道它在哪里。我试着看一下源代码,但是不能理解它。以下是我所看到的一个示例,大大简化了:
我正在使用Python 3.5.2(Anaconda v4.2.0)。我正在使用importlib,这就是我想要坚持的。我也希望能够用vanilla python-3做到这一点。
我从python docs here获得了源代码的导入(是的,我知道这是Python 3.6文档)。
我的主要推动者......
# main.py
import importlib.util
import sys
def foo():
spec = importlib.util.spec_from_file_location('a', 'a.py')
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
print(sys.getrefcount(module))
del module
del spec
if __name__ == '__main__':
foo()
print('THE END')
我的样本模块......
# a.py
print('hello from a')
class A():
def __del__(self):
print('SO LONG A!')
inst = A()
输出:
python main.py
HELLO FROM A!
2
THE END
SO LONG A!
我希望看到“太长了!”在“THE END”之前打印。那么,这个对我的模块的其他隐藏引用在哪里?我明白我的del是无偿的,因为我把它包含在一个函数中。我只是希望删除和范围是明确的。如何让a.py完全卸载?我计划动态加载像a.py这样的大量模块,而且我不想再坚持使用它们了。有什么我想念的吗?
答案 0 :(得分:0)
这里有一个循环引用,模块对象引用再次引用该模块的对象。
这意味着模块不会立即清除(因为引用计数永远不会自动变为0)。您需要等待垃圾收集器破坏圆圈。
您可以致电gc.collect()
强制执行此操作:
import gc
# ...
if __name__ == '__main__':
foo()
gc.collect()
print('THE END')
有了这个,输出变为:
$ python main.py
hello from a
2
SO LONG A!
THE END