2013-04-03 107 views
0

說我有這樣的目錄結構:Python打包 - 這__init__.py的

mydir 
    __init__.py 
    innerdir 
     __init__.py 
     mymodule.py 

mymodule.py的內容很簡單:

def hi(): 
    print 'hello, welcome' 

同時兼具__init__.py S的是

現在,如果我是mydir目錄之外,我打開一個Python提示,並嘗試import mydir然後用mydir.innerdir,我得到一個錯誤(NameError: 'innerdir' is not defined)。

同樣,如果我搬入mydir目錄,提示那裏,並嘗試import innerdirinnerdir.mymodule

我可以成功地import mydir.innerdir,但我只能用它作爲mydir.innerdir,而不僅僅是innerdir

+1

你應該可以'從mydir import innerdir'現在你不必使用整個路徑 – dm03514 2013-04-03 23:25:21

+0

你看了[Packages](http://docs.python.org/2/tutorial/modules.html #packages)在教程中?它解釋了我想你所問的幾乎所有問題。 – abarnert 2013-04-03 23:28:53

+0

@abarnert我真的讀過它,但我並不理解整個概念,我只是迷失了 – whatyouhide 2013-04-03 23:35:29

回答

3

你描述的一些東西,我甚至不知道你期望它做什麼。但是從最後一段來看,這聽起來像你很接近,所以我們從那裏開始。

我可以成功導入mydir.innerdir,但是我只能將它作爲mydir.innerdir使用,而不僅僅是innerdir。爲什麼我必須指定整個路徑?

那怎麼import作品在Python中,即使你忽略的包,只是有一堆東西持平,甚至只是標準庫。例如,如果您import os,則可以執行os.listdir('.'),但不能僅僅執行listdir('.')

這裏的解決方案是一樣的,因爲它是有:

from mydir import innerdir 

這其實不是非常有用,因爲innerdir是什麼也沒有包在裏面直接定義。你可能真的想要做的是from mydir.innerdir import mymodule。但這是如何去做你所問的。


如果你想知道爲什麼後面mydir.innerdirimport mydir不工作,我可以解釋一下。

從教程的Packages部分:

...使用語法等import item.subitem.subsubitem時,除了最後的每個項目必須是一個包;最後一項可以是模塊或包,但不能是上一項中定義的類或函數或變量。

所以,你在做什麼不應該做任何有用的事情。但它實際上做了什麼?

它將包導入,就好像它是一個模塊。這意味着你在包本身定義的任何東西 - 函數,類,甚至模塊 - 將作爲mydir的成員提供。但是這並不會自動導入軟件包目錄中的任何子軟件包或子模塊 - 請記住,您將作爲模塊而不是作爲軟件包導入。


如果你問,當你從內mydir運行(或將其添加到您的PYTHONPATH)會發生什麼......嗯,在這種情況下,mydir不是包的話,那只是一個完整的目錄的模塊和包裝(在這種情況下,只有一個包裝,innerdir)。這很像做from mydir import innerdir

+0

好吧,這很公平。所以這導致了什麼是最初的問題:請參閱我的文章的編輯。 – whatyouhide 2013-04-03 23:27:15

+0

@whatyouhide:究竟是什麼原始問題?你提到了很多不同的東西。你問爲什麼'import mydir; mydir.innerdir'是一個'AttributeError'? – abarnert 2013-04-03 23:27:43

+0

已編輯,問題已解決 – whatyouhide 2013-04-03 23:34:57

1

一個包直接導入不自動把子包或子到它的命名空間:

>>> import mydir 
>>> dir(mydir) 
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__'] 

(注意,沒有innerdir在這裏。)

但是,如果導入通過一個Python將命名空間連接在一起:

>>> import mydir.innerdir 
>>> dir(mydir) 
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'innerdir'] 
>>> dir(mydir.innerdir) 
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__'] 

(請注意,沒有mymodulemydir.innerdir

Python允許你明確地說什麼一些子模塊中使用__all__魔術變量在__init__.py包自動包括,但默認情況下它只是運行代碼__init__.py代碼,而不是做別的事。

你可以做任何以下的:

import mydir.innerdir.mymodule; mydir.innerdir.mymodule.hi() 
from mydir.innerdir import mymodule; mymodule.hi() 
from mydir.innerdir.mymodule import hi; hi() 

或者,您可以編輯__init__.py文件,包括__all__瓦爾通配符進口。

# file mydir/innerdir/__init__.py 
print 'Running mydir/innerdir/__init__.py' 
__all__ = ['mymodule'] 

然後,你可以做這樣的東西:

from mydir.innerdir import *; mymodule.hi() 

甚至更​​瘋狂的,你可以急切地進口的子包和模塊(我不建議這樣做!):

# file mydir/__init__.py 
print 'Running mydir/__init__.py' 
import innerdir 

# file mydir/innerdir/__init__.py 
print 'Running mydir/innerdir/__init__.py' 
import mymodule 

現在這些將起作用:

import mydir; mydir.innerdir.mymodule.hi() 
from mydir import innerdir; innerdir.mymodule.hi() 

你可能想要刷新一下documentation for packages,它解釋了所有這些,並且具有與你在這裏顯示的完全一樣的目錄結構。

+0

非常有趣。你提到的最後一個選項實際上是我所期望的。爲了好奇,是不是您提到的一些內置Python包使用的最後一個選項?例如,當你導入os時,你可以使用'os.path.isdir',這讓我認爲'path'是一個模塊。這意味着'os'既是模塊('os.exit()')**也是**包? – whatyouhide 2013-04-04 08:34:27

+0

包通常不會急於加載子包和子模塊。然而,許多包在它們的'__init__'中有代碼需要一些模塊,所以這些模塊將作爲導入的副作用在包名稱空間中。 – 2013-04-04 08:45:04

+0

順便說一句,這沒有完成的原因是使用一個包的任何一個部分不需要解析和加載到每個單個子包和子模塊中的每個單一定義的內存中。對於大型軟件包來說,這會在內存使用和啓動時間方面產生巨大的差異!避免急於加載'__init__',除非你有一個非常有說服力的理由! – 2013-04-04 08:48:13