2017-07-27 67 views
1

考慮下面的目錄結構,文件和Python版本是Python 3的進口異常

parent 
├── __init__.py 
├── mod1.py 
├── mod2.py 
└── mod3.py 

內容,

$ cat __init__.py 
from . import mod1 
hello = "parent Hello" 

$ cat mod1.py 
from . import mod2 
hello = "parent.mod1 Hello" 

$ cat mod2.py 
hello = "parent.mod2 hello" 

$ cat mod3.py 
hello = "parent.mod3 Hello" 

$ python3 -V 
Python 3.5.2 
在交互式會話我得到以下行爲

現在,

>>> import parent 
>>> parent.mod1 
<module 'parent.mod1' from '/home/codeman/mydata/local/tmp/parent/mod1.py'> 
>>> parent.mod2 
<module 'parent.mod2' from '/home/codeman/mydata/local/tmp/parent/mod2.py'> 
>>> parent.mod3 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: module 'parent' has no attribute 'mod3' 

爲什麼parent.mod2可以訪問,當我只導入了mod1 t他parent/__int__.py文件? (是否是一個錯誤?)

我知道AttributeError與parent.mod3發生,因爲只有__init__.py文件中導入的模塊在使用import parent語法明確導入父項時纔可訪問。

+3

'mod2'是可以訪問的,因爲你在'mod1'中導入了它 – vaultah

+0

@vaultah不應該只在'parent.mod1'中可見?我沒有將它導入'__init __。py'中。 – codeman48

+3

簡短的回答是:它在哪裏輸入並不重要。 'mod2'屬性被添加到「共享」的「父」模塊對象中。如果你有'父'對象,你可以在任何地方訪問'mod2'屬性。 – vaultah

回答

1

無論何時您導入模塊,Python都會創建一個模塊對象並將其存儲在sys.modules字典中。隨後導入同一模塊將重新使用sys.modules中的模塊對象。另外,每次輸入一個sub模塊時,該屬性都會添加到父模塊對象中。

對於給定的Python進程,有一個sys.modules實例,因此一般每個Python進程只有一個模塊實例。這意味着,如果您有權訪問模塊對象,則還可以訪問已導入當前進程中任何位置的子模塊。

在此特定情況下,import package運行包/ __ init__.py,其中進口package.mod1,其中進口package.mod2。因此,mod1mod2被添加到「共享」parent模塊對象,並且您可以訪問它們。

+0

第二段的最後一行總結了整個事情。謝謝!在從x.y import z'輸入stmt後,我看到sys.modules中也導入了x和y。如果z是一個不需要父模塊的'__init __。py'處理的子模塊/程序包,是否可以避免它們的導入(用於加速)? – codeman48

+0

@ codeman48每個'__init __。py'應該只運行一次,所以除非他們需要很多資源(他們不應該),我不會擔心它。無論如何,我不知道有一個乾淨的方法來做到這一點。如果'z'只是'x' /'y'的外圍設備,我會考慮將'x'(或它的子模塊)分成[名稱空間包](https://www.python.org/dev/peps/pep- 0420 /)(這些定義沒有'__init __。py'文件)。 – vaultah