sys.modules 和 globals() 中的模块名称

10 投票
3 回答
7207 浏览
提问于 2025-04-16 23:57

如果我导入一个模块,这个模块的名字会同时出现在 sys.modulesglobals() 中。如果我再把它删除,它会从 globals() 中消失,但仍然保留在 sys.modules 里。为什么会这样呢?

import mymodule
'mymodule' in globals()   # True
'mymodule' in sys.modules # True
del mymodule
'mymodule' in globals()   # False
'mymodule' in sys.modules # Still True, why?

我还发现了以下的不同之处:

from mypackage import mymodule
'mypackage' in sys.modules            # True
'mymodule'  in sys.modules            # False !
'mypackage.mymodule' in sys.modules   # also True !

虽然这些答案对于 globals() 是互补的:

'mypackage' in sys.modules            # False
'mymodule'  in sys.modules            # True 
'mypackage.mymodule' in sys.modules   # False

3 个回答

3

因为Python会把模块缓存到 sys.modules 中,这样可以避免每次都去寻找模块(这个过程比较耗时和慢),从而提高效率。

如果需要的话,可以从 sys.modules 中删除模块,虽然使用 reload 也可能有效。


更详细地说,当你执行 import mymodule 时,会发生一些事情。假设 mymodule 不是解释器自带的模块,以下是大致的步骤:

  1. 解释器会运行一些复杂的代码来找到包含 mymodule 的文件(这个文件可能是 mymodule.pymymodule.pycmymodule.pyd,或者是我没想到的其他文件)。它会在当前目录、sys.path 以及其他地方查找。

  2. 找到的文件会被分析、解析,并在必要时编译成解释器可以理解的字节码。

  3. 编译后的模块会被执行,从而生成一个模块对象。

  4. 这个模块对象会被插入到 sys.modules 中。

  5. 模块对象会被绑定到 import 语句中指定的本地变量。

(以上是我对 import 背后机制的粗略回忆,可能在某些重要和细微的地方不太准确。)

需要注意的是,将模块对象绑定到本地名称其实只是导入过程中的一个小部分。通过执行 del mymodule 来删除名称绑定,并不会影响导入的其他部分。

4

del 是用来删除一个名字和它所指向的内容之间的联系,它只是在特定的范围内起作用;这和模块本身没有直接关系。

sys.modules 列出了所有已经加载的模块,不管这些模块在你的程序中有没有和任何名字绑定。

4

就像其他任何Python对象一样,一个模块会一直存在,直到没有人再引用它。换句话说,sys.modules就像一个普通的字典一样,

import mymodule
lst = {mymodule.__name__: mymodule}
'mymodule' in globals()   # True
'mymodule' in lst         # True
del mymodule
'mymodule' in globals()   # False
'mymodule' in lst         # Still True

在导入模块时,Python只会查看sys.modules。如果你从sys.modules中删除一个模块,下次导入时,Python会重新加载这个模块。

撰写回答