来自<module> import ... in __init__.py使模块名称可见?</module>

时间:2011-05-18 17:40:13

标签: python python-import

采用以下代码示例:

档案package1/__init__.py

from moduleB import foo
print moduleB.__name__

档案package1/moduleB.py

def foo(): pass

然后从当前目录:

>>> import package1
package1.moduleB

此代码适用于CPython。让我感到惊讶的是,from ... import语句中的__init__.py使moduleB名称可见。根据{{​​3}},情况并非如此:

  

from表单不绑定模块名称

有人可以解释为什么CPython这样工作吗?有没有详细描述这个的文件?

2 个答案:

答案 0 :(得分:6)

文档误导了您,因为它是为了描述从包含它的父包外部导入模块的更常见情况。

例如,在我自己的代码中使用“from example import submodule”,其中“example”是一些完全未连接到我自己的代码的第三方库,不绑定名称“example”。它仍然导入两个示例/ __ init__.py和example / submodule.py模块,创建两个模块对象,并将example.submodule分配给第二个模块对象。

但是,来自子模块的名称“from..import”必须在父包对象上设置子模块属性。考虑一下是否:

  1. 在导入包时执行package / __ init__.py。

  2. __init__“来自子模块导入名称”。

  3. 稍后,其他完全不同的代码会“导入package.submodule”。

  4. 在步骤3,sys.modules [“package.submodule”]不存在,在这种情况下再次加载它将为您提供两个不同范围的不同的模块对象;或sys.modules [“package.submodule”]将存在,但“submodule”将不是父包对象的属性(sys.modules [“package”]),“import package.submodule”将不执行任何操作。但是,如果它什么都不做,则使用import的代码无法访问子模块作为包的属性!


    理论上,如果导入机器的其余部分更改为匹配,则可以更改导入子模块的方式。

    如果你只需要知道从包P中导入子模块S会做什么,那么简而言之:

    1. 确保导入P,否则导入P. (此步骤递归处理“import A.B.C.D”。)
    2. 执行S.py以获取模块对象。 (跳过.pyc文件的详细信息等)
    3. 将模块对象存储在sys.modules [“P.S”]。
    4. setattr(sys.modules["P"], "S", sys.modules["P.S"])
    5. 如果导入的格式为“import P.S”,请在本地范围内绑定“P”。

答案 1 :(得分:0)

这是因为__init__.py在运行时将自身表示为package1模块对象,因此每个.py文件都将被定义为子模块。并重写__all__没有任何意义。您可以创建另一个文件,例如example.py,并在__init__.py中使用相同的代码填充它,它将引发NameError

我认为当__init__.py查找与其他python文件不同的变量时,CPython运行时采用特殊算法,可能是这样的:

looking for variable named "moduleB"
if not found:
   if __file__ == '__init__.py': #dont raise NameError, looking for file named moduleB.py
         if current dir contains file named "moduleB.py":
                      import moduleB
         else:
                    raise namerror