为什么我可以从我删除的路径导入模块?
Why can I import a module from a path I removed?
tl;博士
我在 /tmp
中创建了一个虚拟模块模块,insert
它的路径做 sys.path
,导入虚拟模块,del
当它不再需要时,删除它它 sys.path
而且我仍然可以导入它。为什么?
完整问题
考虑这个 pytest 夹具代码及其注释:
def test_function(temp_dir):
with open(os.path.join(temp_dir, 'dum.py'), 'w') as f:
f.write("""
class A:
\"\"\"
test docstring
\"\"\"
test: int
test_2: str = "asdf"
class B(A):
pass
""")
import sys
sys.path.insert(1, temp_dir)
assert temp_dir in sys.path # assertion passes
# noinspection PyUnresolvedReferences
import dum # import successful
yield dum
# teardown executed after each usage of the fixture
del dum # deletion successful
sys.path.remove(temp_dir) # removing from path successful
assert temp_dir not in sys.path # assertion passes
with pytest.raises(ModuleNotFoundError): # fails - importing dum is successful
import dum
为什么?我如何实际删除它?即使我通过执行 sys.path = []
强制 sys.path 为空,它也会发生。项目目录中的任何地方都没有 dum.py
。我错过了什么吗? Python 是否在删除导入的模块后缓存它们?
导入一次模块后,下次要导入时,Python首先检查已导入模块的集合,并使用已加载的模块。因此,第二次导入模块时,sys.path
连查询都没有
如果您想到这一点,这是必不可少的:假设您直接导入一些模块,并且每个模块都使用其他一些模块,等等。如果必须从磁盘检索模块并进行解析,则每次遇到 import
语句时,您将花费大量时间等待模块加载。
还值得注意的是,模块 A 第二次导入模块 B 时,实际上什么也没有发生。有一些方法可以明确地重新加载一个已经加载的模块,但通常,您不想这样做(具有实时更新的 Web 服务器是一个明显的例外)。
Amitai Irron in 提供了非常详细的信息,所以去那里了解 为什么 。要回答如何实际删除它(并且不能再次导入)的问题,您不仅需要执行原始问题的所有删除,还需要:
del sys.modules['dum']
这将从保留所有缓存模块的 sys.modules
中删除模块。感谢 0x5453 将我指向 sys.modules
。
tl;博士
我在 /tmp
中创建了一个虚拟模块模块,insert
它的路径做 sys.path
,导入虚拟模块,del
当它不再需要时,删除它它 sys.path
而且我仍然可以导入它。为什么?
完整问题
考虑这个 pytest 夹具代码及其注释:
def test_function(temp_dir):
with open(os.path.join(temp_dir, 'dum.py'), 'w') as f:
f.write("""
class A:
\"\"\"
test docstring
\"\"\"
test: int
test_2: str = "asdf"
class B(A):
pass
""")
import sys
sys.path.insert(1, temp_dir)
assert temp_dir in sys.path # assertion passes
# noinspection PyUnresolvedReferences
import dum # import successful
yield dum
# teardown executed after each usage of the fixture
del dum # deletion successful
sys.path.remove(temp_dir) # removing from path successful
assert temp_dir not in sys.path # assertion passes
with pytest.raises(ModuleNotFoundError): # fails - importing dum is successful
import dum
为什么?我如何实际删除它?即使我通过执行 sys.path = []
强制 sys.path 为空,它也会发生。项目目录中的任何地方都没有 dum.py
。我错过了什么吗? Python 是否在删除导入的模块后缓存它们?
导入一次模块后,下次要导入时,Python首先检查已导入模块的集合,并使用已加载的模块。因此,第二次导入模块时,sys.path
连查询都没有
如果您想到这一点,这是必不可少的:假设您直接导入一些模块,并且每个模块都使用其他一些模块,等等。如果必须从磁盘检索模块并进行解析,则每次遇到 import
语句时,您将花费大量时间等待模块加载。
还值得注意的是,模块 A 第二次导入模块 B 时,实际上什么也没有发生。有一些方法可以明确地重新加载一个已经加载的模块,但通常,您不想这样做(具有实时更新的 Web 服务器是一个明显的例外)。
Amitai Irron in
del sys.modules['dum']
这将从保留所有缓存模块的 sys.modules
中删除模块。感谢 0x5453 将我指向 sys.modules
。