强制 Unload/Deconstruction 从源动态导入文件
Forcing Unload/Deconstruction of Dynamically Imported File from Source
长期浏览 SO,终于提出自己的问题!
因此,我正在编写一个自动化程序 script/module,它递归地在目录中查找具有特定名称的 python 模块。如果我找到具有该名称的模块,我会动态加载它,从中提取我需要的内容,然后卸载它。我注意到虽然简单地删除模块并没有删除对该模块的所有引用,但在某处还有另一个挥之不去,我不知道它在哪里。我试着看一眼源代码,但无法很好地理解它。这是我所看到的示例,已大大简化:
我正在使用 Python 3.5.2 (Anaconda v4.2.0)。我正在使用 importlib,这就是我想要坚持的。我也希望能够用 vanilla python-3 做到这一点。
我从 python 文档 here 中获取了源代码导入(是的,我知道这是 Python 3.6 文档)。
我的主要driver...
# 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" 之前看到 "SO LONG A!"。那么,对我的模块的其他隐藏引用在哪里?我知道我的 del 是无偿的,因为我将它包装在一个函数中。我只是想让删除和范围明确。如何让 a.py 完全卸载?我计划动态加载大量模块,例如 a.py,并且我不想在实际需要的时候再坚持下去。有什么我想念的吗?
这里有一个循环引用,模块对象引用了再次引用模块的对象
这意味着模块不会立即被清除(因为引用计数本身永远不会变为 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
长期浏览 SO,终于提出自己的问题!
因此,我正在编写一个自动化程序 script/module,它递归地在目录中查找具有特定名称的 python 模块。如果我找到具有该名称的模块,我会动态加载它,从中提取我需要的内容,然后卸载它。我注意到虽然简单地删除模块并没有删除对该模块的所有引用,但在某处还有另一个挥之不去,我不知道它在哪里。我试着看一眼源代码,但无法很好地理解它。这是我所看到的示例,已大大简化:
我正在使用 Python 3.5.2 (Anaconda v4.2.0)。我正在使用 importlib,这就是我想要坚持的。我也希望能够用 vanilla python-3 做到这一点。
我从 python 文档 here 中获取了源代码导入(是的,我知道这是 Python 3.6 文档)。
我的主要driver...
# 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" 之前看到 "SO LONG A!"。那么,对我的模块的其他隐藏引用在哪里?我知道我的 del 是无偿的,因为我将它包装在一个函数中。我只是想让删除和范围明确。如何让 a.py 完全卸载?我计划动态加载大量模块,例如 a.py,并且我不想在实际需要的时候再坚持下去。有什么我想念的吗?
这里有一个循环引用,模块对象引用了再次引用模块的对象
这意味着模块不会立即被清除(因为引用计数本身永远不会变为 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