每當(dāng)我想搞透一個(gè)東西的時(shí)候隘竭,我就會(huì)寫篇文章。OK讼渊,今天的主題就是這個(gè)__init__文件动看。
關(guān)于這個(gè)文件,問題無非是三個(gè)爪幻,是什么菱皆,為什么,怎么用挨稿。
是什么- python包管理
這個(gè)問題的核心在于python的包管理仇轻。
python使用包來組織模塊的命名空間。A.B表名在A包中的B模塊奶甘。主要用來解決全局變量名稱沖突的問題拯田。
為什么
來看一個(gè)典型的項(xiàng)目結(jié)構(gòu):
在導(dǎo)入一個(gè)包的時(shí)候,python搜索所有sys.path下面的目錄甩十。__init__.py文件用來告訴python,這個(gè)目錄是一個(gè)python包。
這個(gè)機(jī)制防止某些通用名字的目錄吭产,例如string侣监,和后續(xù)加載的實(shí)際可能的模塊名發(fā)生沖突。
怎么用
import語句
最簡單的情況下臣淤,__init__.py文件可以是空的橄霉。也可以執(zhí)行初始化代碼,或者設(shè)置__all__變量邑蒋。
包的用戶可以導(dǎo)入包中的單獨(dú)的某個(gè)模塊姓蜂,例如:
import sound.effcts.echo
這會(huì)加載子模塊sound.effcts.echo,使用時(shí)必須使用全名:
sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)
另外一種導(dǎo)入包的方式是:
from sound.effects import echo
這也會(huì)加載子模塊echo, 使用時(shí)不需要使用全名:
echo.echofilter(input, output, delay=0.7, atten=4)
也可以直接導(dǎo)入某個(gè)函數(shù):
from sound.effects.echo import echofilter
這會(huì)加載子模塊echo医吊,但是函數(shù)echofilter()直接可用:
echofilter(input, output, delay=0.7, atten=4)
在使用from package import item語法時(shí)钱慢,item可以是package的子模塊、子包或者任何定義在packge里的名字卿堂。例如一個(gè)函數(shù)束莫、類或變量懒棉。import聲明首先假設(shè)item是package里定義的,如果不是览绿,會(huì)假設(shè)他是一個(gè)模塊并嘗試加載策严。加載失敗會(huì)拋出importerror.
使用import item.subitem.subsubitem的時(shí)候,除了嘴后一個(gè)Item饿敲,其他的Item都必須是包妻导。最后一個(gè)item可以是一個(gè)模塊,一個(gè)包怀各,但不能是類或者函數(shù)倔韭、變量。
import * from a package
當(dāng)用戶書寫from sound.effects import *
時(shí)會(huì)發(fā)生什么渠啤?理想情況下狐肢,這種方式能進(jìn)入文件系統(tǒng),找到程序包中存在哪些子模塊沥曹,然后將其全部導(dǎo)入份名。這可能會(huì)花費(fèi)很長時(shí)間,并且導(dǎo)入子模塊可能會(huì)產(chǎn)生有害的副作用妓美,這些副作用只有在明確導(dǎo)入子模塊時(shí)才會(huì)發(fā)生僵腺。
唯一的解決方案是讓程序包作者提供程序包的顯式索引。該import
語句使用以下約定:如果程序包的 __init__.py
代碼定義了名為的列表__all__
壶栋,則將其視為遇到時(shí)應(yīng)導(dǎo)入的模塊名稱的列表辰如。發(fā)行新版本的軟件包時(shí),軟件包作者有責(zé)任使此列表保持最新贵试。如果軟件包作者看不到從軟件包中導(dǎo)入*的用途琉兜,他們可能還會(huì)決定不支持它。例如毙玻,該文件可能包含以下代碼:
__all__ = ["echo", "surround", "reverse"]
這意味著from sound.effects import *
將導(dǎo)入sound
包的三個(gè)命名子模塊豌蟋。
如果__all__
沒有定義,語句 也不會(huì)導(dǎo)入從包中的所有子模塊到當(dāng)前的命名空間; 它僅確保已導(dǎo)入包sound.effects(可能運(yùn)行__init__.py中任何初始化代碼)桑滩,然后導(dǎo)入包中定義的任何名稱梧疲。這包括由__init__.py定義的任何名稱(以及明確加載的子模塊)。它還包括程序包的所有子模塊运准,這些子模塊由先前的語句顯式加載幌氮。考慮以下代碼:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
在此示例中胁澳,echo
和surround
模塊被導(dǎo)入當(dāng)前名稱空間中该互,因?yàn)樗鼈冊趫?zhí)行語句sound.effects
時(shí)在包中定義from...import
。(這在__all__
定義時(shí)也適用 韭畸。)
盡管某些模塊被設(shè)計(jì)為僅在使用時(shí)導(dǎo)出遵循某些模式的名稱慢洋,但在生產(chǎn)代碼中import *
仍被認(rèn)為是不好的做法塘雳。
記住,使用from package import specific_submodule
沒什么錯(cuò)普筹。實(shí)際上败明,這是推薦的表示法,除非導(dǎo)入模塊需要使用來自不同軟件包的具有相同名稱的子模塊太防。