python中相同模块的两个实例有问题吗?

时间:2019-11-26 14:06:22

标签: python

我有两个模块,如下所示:

模块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不同吗?

1 个答案:

答案 0 :(得分:3)

遇到import语句时,解释器会在sys.modules中寻找相应的键。如果找到了密钥,则该密钥将绑定到您请求的名称。如果不是,则在sys.modules中创建一个新的空模块对象,然后进行填充。这样做的原因正是为了避免循环导入的无限循环。

运行模块时,模块将以名称__main__导入。你可以

以下是当您将moda作为脚本运行时的事件顺序:

  1. moda.py的形式开始加载sys.modules['__main__']。此时,这只是一个空的命名空间
  2. import modb中遇到了
  3. moda.py。为sys.modules['modb']创建了新的空名称空间。
  4. import moda中遇到了
  5. modb.py。为sys.modules['moda']创建了新的空名称空间。请注意,这与步骤1中的sys.modules['__main__'] 是同一对象。
  6. import modb中遇到了
  7. moda.py。由于sys.modules['modb']存在,因此它与moda中的该名称绑定
  8. 由于moda.py当前正在以名称moda加载,因此它完成了其命名空间的填充,而没有运行导入保护的
  9. modb.py完成填充其名称空间(从步骤2开始)并运行print('modb loaded')
  10. __main__中定义的
  11. moda.py完成了其命名空间的填充(从步骤1开始)并运行了导入保护。

希望这可以帮助您可视化发生的情况。您已经加载了三个模块,而不是两个模块,因为moda是以两个不同的名称加载的,并且是两个完全不同的模块对象。

__main__中的导入保护调用__main__.main,该操作将执行以下操作:

  1. 设置__main__.x = 42moda.x仍为None
  2. __main__.printx打印__main__.x,即42
  3. modb.printx调用moda.printx,打印moda.x,即None
  4. __main__.printx再次打印__main__.x,仍然是42