简体   繁体   English

导入模块:__main__ vs作为模块导入

[英]Importing modules: __main__ vs import as module

To preface, I think I may have figured out how to get this code working (based on Changing module variables after import ), but my question is really about why the following behavior occurs so I can understand what to not do in the future. 作为序言,我想我可能已经弄清楚了如何使此代码正常工作(基于import之后更改模块变量 ),但是我的问题确实是关于为什么会发生以下行为,以便我将来可以做什么。

I have three files. 我有三个文件。 The first is mod1.py: 第一个是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()

Next I have mod2.py: 接下来我有mod2.py:

# mod2.py

import mod1

def func2():
    mod1.func1B()

Finally I have driver.py: 最后我有driver.py:

# driver.py

import mod1

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

If I execute the command python mod1.py then the output is None . 如果我执行命令python mod1.py则输出为None Based on the link I referenced above, it seems that there is some distinction between mod1.py being imported as __main__ and mod1.py being imported from mod2.py . 根据我上面提到的链路上,似乎有一些区分mod1.py为被进口__main__mod1.py正在从进口mod2.py Therefore, I created driver.py . 因此,我创建了driver.py If I execute the command python driver.py then I get the expected output: A . 如果执行命令python driver.py则会得到预期的输出: A I sort of see the difference, but I don't really see the mechanism or the reason for it. 我看到了一些区别,但是我并没有真正看到它的机制或原因。 How and why does this happen? 这是怎么发生的以及为什么发生的? It seems counterintuitive that the same module would exist twice. 似乎同一模块将存在两次是违反直觉的。 If I execute python mod1.py , would it be possible to access the variables in the __main__ version of mod1.py instead of the variables in the version imported by mod2.py ? 如果我执行python mod1.py ,是否可以访问mod1.py__main__版本中的变量,而不是mod2.py导入的版本中的变量?

The __name__ variable always contains the name of the module, except when the file has been loaded into the interpreter as a script instead. __name__变量始终包含模块的名称, 除非文件已作为脚本加载到解释器中。 Then that variable is set to the string '__main__' instead. 然后将该变量设置为字符串'__main__'

After all, the script is then run as the main file of the whole program, everything else are modules imported directly or indirectly by that main file. 毕竟,脚本随后将作为整个程序的主文件运行,其他所有文件都是该主文件直接或间接导入的模块。 By testing the __name__ variable, you can thus detect if a file has been imported as a module, or was run directly. 通过测试__name__变量,您可以因此检测文件是作为模块导入的还是直接运行的。

Internally, modules are given a namespace dictionary, which is stored as part of the metadata for each module, in sys.modules . 在内部,为模块提供了一个命名空间字典,该字典作为每个模块的元数据的一部分存储在sys.modules The main file, the executed script, is stored in that same structure as '__main__' . 主文件(已执行的脚本)以与'__main__'相同的结构存储。

But when you import a file as a module, python first looks in sys.modules to see if that module has already been imported before. 但是,当您将文件导入为模块时,python首先在sys.modules查找该模块是否已经导入。 So, import mod1 means that we first look in sys.modules for the mod1 module. 因此, import mod1意味着我们首先在sys.modules查找mod1模块。 It'll create a new module structure with a namespace if mod1 isn't there yet. 如果还没有mod1它将创建一个带有名称空间的新模块结构。

So, if you both run mod1.py as the main file, and later import it as a python module, it'll get two namespace entries in sys.modules . 因此,如果您都将mod1.py作为主文件运行, 然后将其作为python模块导入,则它将在sys.modules获得两个命名空间条目。 One as '__main__' , then later as 'mod1' . 一个是'__main__' ,然后是'mod1' These two namespaces are completely separate. 这两个名称空间是完全分开的。 Your global var1 is stored in sys.modules['__main__'] , but func1B is looking in sys.modules['mod1'] for var1 , where it is None . 您的全局var1存储在sys.modules['__main__'] ,但是func1Bsys.modules['mod1']查找var1 ,其中为None

But when you use python driver.py , driver.py becomes the '__main__' main file of the program, and mod1 will be imported just once into the sys.modules['mod1'] structure. 但是,当您使用python driver.pydriver.py成为程序的'__main__'主文件,并且mod1将仅一次导入sys.modules['mod1']结构中。 This time round, func1A stores var1 in the sys.modules['mod1'] structure, and that's what func1B will find. 这次, func1Avar1存储在sys.modules['mod1']结构中,这就是func1B会发现的。

Regarding a practical solution for using a module optionally as main script - supporting consistent cross-imports: 关于将模块可选地用作主脚本的实用解决方案-支持一致的交叉导入:

Solution 1: 解决方案1:

See eg in Python's pdb module, how it is run as a script by importing itself when executing as __main__ (at the end) : 参见例如在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()

Just I would recommend to reorganize the __main__ startup to the beginning of the script like this: 我只是建议将__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
...

This way the module body is not executed twice - which is "costly", undesirable and sometimes critical. 这样,模块主体不会执行两次-这是“昂贵的”,不希望的,有时甚至很关键。

Solution 2: 解决方案2:

In rarer cases it is desirable to expose the actual script module __main__ even directly as the actual module alias ( mod1 ): 在极少数情况下,最好甚至将实际脚本模块__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()

Known drawbacks: 已知缺点:

  • reload(_mod) fails reload(_mod)失败
  • pickle'ed classes would need extra mappings for unpickling ( find_global ..) 腌制的类将需要额外的映射才能进行find_globalfind_global ..)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将模块导入为 __main__? - How to import a module as __main__? Python,从同一模块导入:ImportError:无法导入名称'blah',__name__ =='__main__' - Python, importing from same module: ImportError: cannot import name 'blah', __name__ == '__main__' 为什么'__main__'中的导入模块不允许multiprocessig使用模块? - Why does importing module in '__main__' not allow multiprocessig to use module? 作为__main__程序执行时,在同级目录中导入模块 - Importing a module in sibling dir while being executed as a __main__ program 如何从 python 中的 __main__ 导入相关模块 - How to import relative module from __main__ in python 导入模块失败,因为 __name__ 是 __main__ - Import in a module fails because __name__ is __main__ Google DataFlow/Python:在 __main__ 中使用 save_main_session 和自定义模块导入错误 - Google DataFlow/Python: Import errors with save_main_session and custom modules in __main__ Python 3 - 在同一目录中导入.py文件 - ModuleNotFoundError:没有名为'__main __。char'的模块; '__main__'不是包 - Python 3 - importing .py file in same directory - ModuleNotFoundError: No module named '__main__.char'; '__main__' is not a package ModuleNotFoundError:没有名为'__main __。web_app'的模块; 从子文件夹导入包时,'__ main__'不是包 - ModuleNotFoundError: No module named '__main__.web_app'; '__main__' is not a package while importing package from sub folder 使用 __main__ 方法导入 python - import python with __main__ method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM