8

主要.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__']

importin__init__.py没有按预期工作。请注意,全局命名空间有一个“foo”,它应该只绑定到本地“mod”

甚至 exec "import foo as mod" in {'__name__': __name__, '__path__': __path__} 无法阻止全局命名空间被修改

这怎么可能发生?

4

1 回答 1

4

啊! 棘手,但我明白了!

“foo”不是一个简单的“其他包”——Python 认为它是“包”模块的子模块。

当您第一次运行“包”时 - 从外部脚本导入它,或者使用-m命令行开关运行它(但如果您python package/__init__.py直接从命令行运行,则不会),“包”模块被解析,并添加到sys.modules字典(在sys模块上)。

读取子模块时foo,除了直接放在sys.moduleskey 下["package.foo"],还设置为其父模块的属性。因此,它可以在您的 Python 应用程序中作为package.foo. 发生的情况是在 , 中设置属性与在运行时在全局变量中sys.modules["package"]设置键具有相同的效果。package/__init__.py这就是正在发生的事情。

我希望我能把这个过程正确地翻译成文字——如果没有,请通过评论再次询问。

-- Since this is probably happening in real code you have, and the equivalent of "do_import" is being called from code outside your package (and have the side effects of making your sub-modules appear on the package's global namespace), there is no easy work around on the way you are doing it. My suggestion is to just add an underscore (_) at the beggining of the sub-modules names if they are not intended to be called from general code from outside your package. (It also won't show up if someone does from package import * in this case)

于 2012-09-24T04:05:13.570 回答