2015-02-11 52 views
0

我有以下的情況,其中一個目錄:相對進口不起作用,貌似找不到模塊

a/ 
    __init__.py 
    first.py 
    second.py 

__init__.py

print('i\'m starting the directory') 
__all__ = ['second', 'first'] 

first.py

print('hi, i\'m the first') 
from . import * 

second.py

print('hi, i\'m the second') 

所以,當我從交互提示符下運行:

>>> import a.first 
i'm starting the directory 
hi, i'm the first 
hi, i'm the second 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/home/antox/Scrivania/a/first.py", line 2, in <module> 
    from . import * 
AttributeError: 'module' object has no attribute 'first' 

爲什麼它不找到first.py模塊?我的意思是我希望沒有錯誤;在進口運行期間,我認爲它可以看到first.py已經加載,所以沒有錯誤,它只是跳到下一個列出的__all__

+0

http://en.wikipedia.org/wiki/Circular_dependency – Vor 2015-02-11 16:11:15

+1

將'import first,second'加入'__init __。py',並從'first.py'中刪除'import'。 – jonrsharpe 2015-02-11 16:14:50

+0

是的,我知道還有其他方法可以獲得相同的好處,但我想知道這種情況下發生了什麼 – zer0uno 2015-02-11 16:17:40

回答

3

這似乎是Python導入機器中的一個長期存在的錯誤。問題在於,一個模塊在完全加載之後纔會被添加到它的包的全局名稱空間中。如果module僅部分加載,則打破from package import module語句。儘管如此,你仍然可以使用import package.module,長期以來,它一直得到進口系統的特別支持。

由於jonrsharpe評論說,Python開發人員已經意識到這個問題since 2004。由於這個問題只會在包含模塊的循環進口產品出現時纔會出現,而且通常認爲循環進口模式是不好的設計,所以他們沒有把修復這個問題放在很高的優先地位。

但是,最近有進展! A partial fix是幾個月前添加的,對於剛剛發佈第一個alpha版本的Python 3.5(完整版本計劃在9月份發佈)。該修復程序在加載時實際上並未將module添加到package,而是在from package import module語句中添加了一個額外的支票,以便它們在先前引發ImportError的循環導入情況下工作。

但是,這並不修復from package import *的情況。通配符導入的代碼顯然仍然需要package.__all__中的所有名稱實際存在於模塊本身中。它似乎沒有檢查sys.modules字典來檢查仍在進行加載的模塊。

那麼,這對您的代碼意味着什麼?我認爲有兩個重要的經驗教訓:首先,如果可以提供幫助,請不要使用循環導入(而是嘗試將兩個模塊中的一些代碼分解爲第三個公用程序模塊)。其次,不要使用通配符導入(如果first.py使用from . import first, second,則在Python 3.5中不會有錯誤)。

+0

對不起,我沒有看到你提供了一個答案。然而,我試着按照你告訴我的方式,我在** __ init __。py **文件中編寫了'first = 0',並且所有工作都很好,但是我無法解決這個問題。 '__all__ = ['second','first']':爲什麼我沒有爲'second''得到同樣的錯誤?爲什麼我不需要插入'second = 0'語句呢?什麼需要明確添加,特別是只是「第一」?什麼機制? – zer0uno 2015-02-12 19:02:55

+0

我強烈懷疑在'__init __。py'中放置'first = 0'會導致更多的困惑,而不是更少。你最終會把'a.first.first'設爲'0',這個可能性不大,而不是你通常期望的'a.first'的引用。你不會有導入'second'的問題,因爲它可以在沒有任何循環的情況下一路加載。加載完成後,放入'a'模塊。另一方面,第一個模塊仍在加載,所以它不能在'a'中找到(儘管如果直接命名,而不是使用'*',3.5中的新代碼將會找到它)。 – Blckknght 2015-02-13 00:25:16

+0

哦,天哪......我很困惑,爲什麼我會有'a.first.first'?與'來自。 import *'我的意思是:導入此目錄中的每個模塊。現在,** __ init__中定義了'first = 0'。py **文件,所以我期望它被連接到'a'目錄模塊(在導入'first.py'的過程中將被覆蓋),所以...我不明白:-( – zer0uno 2015-02-13 01:04:38