导入模块:__main__ VS进口的模块(Importing modules: __main__

2019-06-18 18:53发布

为了前言,我想我可能已经找到了如何让这段代码的工作(根据更改后导入模块的变量 ),但我的问题是真的,为什么会出现以下行为,所以我可以理解将来不会做什么。

我有三个文件。 首先是mod1.py:

# mod1.py

import mod2

var1A = None

def func1A():
    global var1
    var1 = 'A'
    mod2.func2()

def func1B():
    global var1
    print var1

if __name__ == '__main__':
    func1A()

接下来,我有mod2.py:

# mod2.py

import mod1

def func2():
    mod1.func1B()

最后,我有driver.py:

# driver.py

import mod1

if __name__ == '__main__':
    mod1.func1A()

如果我执行命令python mod1.py然后输出为None 。 根据我上面提到的链路上,似乎有一些区分mod1.py被导入为__main__mod1.py正在从进口mod2.py 。 因此,我创建driver.py 。 如果我执行命令python driver.py然后我得到预期的输出: A 。 我有点看出差别,但我实在不明白的机构或它的原因。 如何以及为什么会发生这种情况? 这似乎违反直觉的,同样的模块将存在两次。 如果我执行python mod1.py ,这将是可以访问的变量__main__的版本mod1.py由进口版本,而不是变量mod2.py

Answer 1:

__name__变量总是包含模块,当文件被加载到解释为脚本,而不是除了名。 然后该变量被设置为字符串'__main__'来代替。

毕竟,脚本然后运行作为整个程序的主文件,其他的一切都是由主文件直接或间接导入的模块。 通过测试__name__变量,因此您能检测一个文件已经导入的模块,或者直接运行。

在内部,模块给出一个命名空间的字典,其被存储为每个模块的元数据的一部分,在sys.modules 。 主文件,执行的脚本,被存储在相同的结构'__main__'

但是,当你输入一个文件作为一个模块,蟒蛇首先查找在sys.modules ,看看是否能模块之前已经进口。 因此, import mod1意味着我们首先在寻找sys.modulesmod1模块。 如果它会创建一个命名空间的一个新的模块结构mod1现在还没有。

所以,如果你都运行mod1.py与主文件, 随后将其导入作为一个Python模块,它会在得到两个命名空间中的条目sys.modules 。 作为一个'__main__' ,后来因为'mod1' 。 这两个命名空间是完全独立的。 您的全球var1存储在sys.modules['__main__']func1B正在寻找在sys.modules['mod1']var1 ,它是None

但是,当你使用python driver.pydriver.py成为'__main__'程序的主文件,和mod1将只是一次导入到sys.modules['mod1']结构。 圆这一次, func1Avar1sys.modules['mod1']的结构,而这正是func1B会发现。



Answer 2:

关于用于使用模块可选地作为主脚本的实际解决方案 - 支撑一致的横进口:

解决方案1:

见例如,在Python的PDB模块,它是如何运行的脚本中的执行时,进口本身__main__ (末):

#! /usr/bin/env python
"""A Python debugger."""
# (See pdb.doc for documentation.)
import sys
import linecache

...

# When invoked as main program, invoke the debugger on a script
if __name__ == '__main__':
    import pdb
    pdb.main()

只是我会建议重组__main__启动,以这样的脚本的开头:

#! /usr/bin/env python
"""A Python debugger."""
# When invoked as main program, invoke the debugger on a script
import sys
if __name__ == '__main__':        
    ##assert os.path.splitext(os.path.basename(__file__))[0] == 'pdb'
    import pdb
    pdb.main()
    sys.exit(0)

import linecache
...

这种方式不执行两倍的模块体 - 这是“昂贵”,不期望的并且有时是至关重要的。

方案2:

在罕见的情况下,希望以暴露实际脚本模块__main__甚至直接作为实际模块别名( mod1 ):

# mod1.py    
import mod2

...

if __name__ == '__main__':
    # use main script directly as cross-importable module 
    _mod = sys.modules['mod1'] = sys.modules[__name__]
    ##_modname = os.path.splitext(os.path.basename(os.path.realpath(__file__)))[0]
    ##_mod = sys.modules[_modname] = sys.modules[__name__]
    func1A()

已知的缺点:

  • reload(_mod)失败
  • pickle'ed类将需要额外的映射取储存( find_global ..)


文章来源: Importing modules: __main__ vs import as module