main.py:
import package
包/ __ INIT __ PY:
# use function to split local and global namespace
def do_import():
print globals().keys()
print locals().keys()
import foo as mod
print locals().keys()
print globals().keys()
do_import()
包/ foo.py:
print 'Hello from foo'
执行main.py将输出如下:
['__builtins__', '__file__', '__package__', '__path__', '__name__', 'do_import', '__doc__']
[]
Hello from foo
['mod']
['__builtins__', '__file__', '__package__', '__path__', '__name__', 'foo', 'do_import', '__doc__']
import
中的__init__.py
无法正常工作。
请注意,全局命名空间有一个'foo',它应该只绑定到本地'mod'
即使是一个
exec "import foo as mod" in {'__name__': __name__, '__path__': __path__}
无法阻止全局命名空间被修改
这怎么可能发生?
答案 0 :(得分:3)
啊!整蛊,但我知道了!
“foo”不是一个简单的“其他包” - 它似乎是Python作为“包”模块的子模块。
首次运行“package”时 - 从外部脚本导入它,或者使用-m
命令行开关运行它(但如果直接从命令行运行python package/__init__.py
则不行) ,解析“package”模块,并将其添加到sys.modules
dicticionary(在sys
模块上)。
当读取子模块foo
时,除了直接放在密钥sys.modules
下的["package.foo"]
下面之外,它还被设置为其父模块的属性。因此,它可以在您的Python应用程序中作为package.foo
使用。发生的事情是在sys.modules["package"]
中设置属性与在运行时在package/__init__.py
全局变量中设置键具有相同的效果。这就是发生的事情。
我希望我能将这个过程正确地翻译成文字 - 如果没有,只需再通过评论再问一遍。
-
因为这可能发生在您拥有的实际代码中,并且相当于“do_import”是从包外部的代码调用的(并且具有使您的子模块出现在包的全局命名空间中的副作用),所以不容易解决你正在做的事情。我的建议是在子模块名称的开头添加下划线(_
),如果它们不打算从包外部的通用代码中调用。 (如果在这种情况下有人from package import *