我有两个模块,如下所示:
模块A-moda.py
import modb
x = None
def printx():
global x
print(x)
def main():
global x
x = 42
printx()
modb.printx()
printx()
if __name__ == '__main__':
main()
模块B-modb.py
import moda
def printx():
moda.printx()
print('modb imported')
当我运行python moda.py
时,得到的输出是:
modb imported
42
None
42
我不明白为什么第二个打印(来自modb.printx())为“无”。我认为python模块表现为单例。我想念什么?
有人可以解释为什么在modb
中导入的模块与原始模块moda
不同吗?
答案 0 :(得分:3)
遇到import
语句时,解释器会在sys.modules
中寻找相应的键。如果找到了密钥,则该密钥将绑定到您请求的名称。如果不是,则在sys.modules
中创建一个新的空模块对象,然后进行填充。这样做的原因正是为了避免循环导入的无限循环。
运行模块时,模块将以名称__main__
导入。你可以
以下是当您将moda
作为脚本运行时的事件顺序:
moda.py
的形式开始加载sys.modules['__main__']
。此时,这只是一个空的命名空间import modb
中遇到了moda.py
。为sys.modules['modb']
创建了新的空名称空间。import moda
中遇到了modb.py
。为sys.modules['moda']
创建了新的空名称空间。请注意,这与步骤1中的sys.modules['__main__']
不是同一对象。import modb
中遇到了moda.py
。由于sys.modules['modb']
存在,因此它与moda
中的该名称绑定moda.py
当前正在以名称moda
加载,因此它完成了其命名空间的填充,而没有运行导入保护的。modb.py
完成填充其名称空间(从步骤2开始)并运行print('modb loaded')
。__main__
中定义的moda.py
完成了其命名空间的填充(从步骤1开始)并运行了导入保护。希望这可以帮助您可视化发生的情况。您已经加载了三个模块,而不是两个模块,因为moda
是以两个不同的名称加载的,并且是两个完全不同的模块对象。
__main__
中的导入保护调用__main__.main
,该操作将执行以下操作:
__main__.x = 42
(moda.x
仍为None
)__main__.printx
打印__main__.x
,即42
modb.printx
调用moda.printx
,打印moda.x
,即None
。__main__.printx
再次打印__main__.x
,仍然是42
。