2016-05-17 59 views
1

我有以下的文件结构,每个代码最多一行(如下图所示)的__init__.py当它是圆形的进口:使用绝对导入和

a 
├── b 
│   ├── c.py   import a.b.d as d 
│   ├── d.py 
│   └── __init__.py from a.b.c import * 
├── __init__.py 
└── main.py   import a.b as b 

通过运行python -m a.main,我得到以下错误:

Traceback (most recent call last): 
    File "/usr/lib/python2.7/runpy.py", line 162, in _run_module_as_main 
    "__main__", fname, loader, pkg_name) 
    File "/usr/lib/python2.7/runpy.py", line 72, in _run_code 
    exec code in run_globals 
    File "/tmp/test/a/main.py", line 1, in <module> 
    import a.b as b 
    File "a/b/__init__.py", line 1, in <module> 
    from a.b.c import * 
    File "a/b/c.py", line 1, in <module> 
    import a.b.d as d 
AttributeError: 'module' object has no attribute 'b' 

我不确定这是否是由循环导入造成的。如果我将import a.b.d as d更改为from a.b import d,则不会再有错误。

+0

from'b.py'你应该只能'输入c'否? –

+0

[This](https://www.youtube.com/watch?v=0oTh1CXRaQ0)虽然有点长,但在处理导入时可能非常有用。 – quapka

+0

@peter我有另一篇文章,涵盖创建和导入自定义模块。如果它可以帮助你,请注册。 http://stackoverflow.com/questions/37072773/how-to-create-and-import-a-custom-module-in-python/37074372#37074372 – PyNoob

回答

2

AttributeError是由文件c.py中的导入语句中的as造成的。

整个过程是这样的:

  1. main.py创建模块a,它加入到sys.modules和初始化它;
  2. main.py创建模块a.b,将其添加到sys.modules并开始执行其代码;
  3. b/__init__.pyaa.b已经在sys.modules)创建模块a.b.c,它加入到sys.modules并开始执行它的代码;
  4. b/c.py创建模块a.b.d,把它添加到sys.modules,执行自身的代码,增加它作为模块a.b,然后试图的属性“d”,但不能结合a.b.d命名d。问题是模块a.b尚未完成初始化,所以属性'b'不在模块a中。

为什么

要理解这一点,你应该知道,一个import语句做两件事情(在Python 2Python 3)。

  1. 查找一个或多个模块,并在必要时初始化它或它们;
  2. 在本地名称空间中定义一个名称并将其绑定到某个模块。

模块查找

前者调用__import__钩,它加载的模块,并对其进行初始化。在Python 2中,默认情况下钩子为imputil.ImportManager._import_hook,它的工作原理与此类似。

  1. 检查模块是否在sys.modules;
  2. 如果没有,找到模块并获取它的代码;
  3. 创建模块并将其添加到sys.modules;
  4. 在模块的名称空间内运行代码;
  5. 返回模块。

如果语句是像import a.b.c,模块发现过程将递归发现模块aa.ba.b.c,并跟踪他们的sys.modules。如果返回模块a.b,则将其设置为模块a的属性“b”。最后,模块查找过程将返回顶层模块a

如果声明与from a.b import c,d相似,则结果稍有不同。在这种情况下,将返回底部模块(即模块a.b)。

名称绑定

如果使用import [module]声明,顶部模块的名称将被绑定到返回值(这是顶层模块)。

如果您使用import [module] as [name]语句,则[name]将被绑定到底层模块(通过访问顶层模块的属性)。

如果您使用的是from [module] import [identifier],则底层模块的名称将绑定到返回值(from import语句是底层模块)。

Example 
import a.b.c   # a <- <module 'a'> 
import a.b.c as c  # c <- <module 'a'>.b.c 
from a.b import c  # c <- <module 'a.b'>.c 

在你的问题,当模块a.b是成功的一半初始化,而不是在模块a的属性尚未登记发生在c.py import语句。因此import as在绑定a.b.cc时会遇到问题。但是,由于模块a.b已经在sys.modules中注册,所以使用from import不会遇到这样的问题。