sys.modules 和 globals() 中的模块名称
如果我导入一个模块,这个模块的名字会同时出现在 sys.modules
和 globals()
中。如果我再把它删除,它会从 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 个回答
因为Python会把模块缓存到 sys.modules
中,这样可以避免每次都去寻找模块(这个过程比较耗时和慢),从而提高效率。
如果需要的话,可以从 sys.modules
中删除模块,虽然使用 reload
也可能有效。
更详细地说,当你执行 import mymodule
时,会发生一些事情。假设 mymodule
不是解释器自带的模块,以下是大致的步骤:
解释器会运行一些复杂的代码来找到包含
mymodule
的文件(这个文件可能是mymodule.py
、mymodule.pyc
或mymodule.pyd
,或者是我没想到的其他文件)。它会在当前目录、sys.path 以及其他地方查找。找到的文件会被分析、解析,并在必要时编译成解释器可以理解的字节码。
编译后的模块会被执行,从而生成一个模块对象。
这个模块对象会被插入到 sys.modules 中。
模块对象会被绑定到
import
语句中指定的本地变量。
(以上是我对 import
背后机制的粗略回忆,可能在某些重要和细微的地方不太准确。)
需要注意的是,将模块对象绑定到本地名称其实只是导入过程中的一个小部分。通过执行 del mymodule
来删除名称绑定,并不会影响导入的其他部分。
del
是用来删除一个名字和它所指向的内容之间的联系,它只是在特定的范围内起作用;这和模块本身没有直接关系。
sys.modules
列出了所有已经加载的模块,不管这些模块在你的程序中有没有和任何名字绑定。
就像其他任何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会重新加载这个模块。