为什么我可以从我删除的路径导入模块?

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