[英]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__']
,但是func1B
在sys.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.py
, driver.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. 这次, func1A
将var1
存储在sys.modules['mod1']
结构中,这就是func1B
会发现的。
Regarding a practical solution for using a module optionally as main script - supporting consistent cross-imports: 关于将模块可选地用作主脚本的实用解决方案-支持一致的交叉导入:
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. 这样,模块主体不会执行两次-这是“昂贵的”,不希望的,有时甚至很关键。
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)
失败 find_global
..) 腌制的类将需要额外的映射才能进行find_global
( find_global
..)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.