2016-05-17 48 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不會遇到這樣的問題。