云計算開發(fā)學(xué)習(xí)筆記:Python3如何從一個包中導(dǎo)入*
設(shè)想一下,如果我們使用 from sound.effects import *會發(fā)生什么?Python 會進(jìn)入文件系統(tǒng),找到這個包里面所有的子模塊,一個一個的把它們都導(dǎo)入進(jìn)來。
但是很不幸,這個方法在 Windows平臺上工作的就不是非常好,因為Windows是一個大小寫不區(qū)分的系統(tǒng)。
在這類平臺上,沒有人敢擔(dān)保一個叫做 ECHO.py 的文件導(dǎo)入為模塊 echo 還是 Echo 甚至 ECHO。
(例如,Windows 95就很討厭的把每一個文件的首字母大寫顯示)而且 DOS 的 8+3 命名規(guī)則對長模塊名稱的處理會把問題搞得更糾結(jié)。
為了解決這個問題,只能煩勞包作者提供一個精確的包的索引了。
導(dǎo)入語句遵循如下規(guī)則:如果包定義文件 __init__.py 存在一個叫做 __all__ 的列表變量,那么在使用 from package import * 的時候就把這個列表中的所有名字作為包內(nèi)容導(dǎo)入。
作為包的作者,可別忘了在更新包之后保證 __all__ 也更新了啊。你說我就不這么做,我就不使用導(dǎo)入*這種用法,好吧,沒問題,誰讓你是老板呢。這里有一個例子,在:file:sounds/effects/__init__.py中包含如下代碼:
這表示當(dāng)你使用from sound.effects import *這種用法時,你只會導(dǎo)入包里面這三個子模塊。
如果 __all__ 真的沒有定義,那么使用from sound.effects import *這種語法的時候,就不會導(dǎo)入包 sound.effects 里的任何子模塊。他只是把包sound.effects和它里面定義的所有內(nèi)容導(dǎo)入進(jìn)來(可能運行__init__.py里定義的初始化代碼)。
這會把 __init__.py 里面定義的所有名字導(dǎo)入進(jìn)來。并且他不會破壞掉我們在這句話之前導(dǎo)入的所有明確指定的模塊。看下這部分代碼:
這個例子中,在執(zhí)行 from...import 前,包 sound.effects 中的 echo 和 surround 模塊都被導(dǎo)入到當(dāng)前的命名空間中了。(當(dāng)然如果定義了 __all__ 就更沒問題了)
通常我們并不主張使用 * 這種方法來導(dǎo)入模塊,因為這種方法經(jīng)常會導(dǎo)致代碼的可讀性降低。不過這樣倒的確是可以省去不少敲鍵的功夫,而且一些模塊都設(shè)計成了只能通過特定的方法導(dǎo)入。
記住,使用 from Package import specific_submodule 這種方法永遠(yuǎn)不會有錯。事實上,這也是推薦的方法。除非是你要導(dǎo)入的子模塊有可能和其他包的子模塊重名。
如果在結(jié)構(gòu)中包是一個子包(比如這個例子中對于包sound來說),而你又想導(dǎo)入兄弟包(同級別的包)你就得使用導(dǎo)入絕對的路徑來導(dǎo)入。比如,如果模塊sound.filters.vocoder 要使用包 sound.effects 中的模塊 echo,你就要寫成 from sound.effects import echo。
無論是隱式的還是顯式的相對導(dǎo)入都是從當(dāng)前模塊開始的。主模塊的名字永遠(yuǎn)是"__main__",一個Python應(yīng)用程序的主模塊,應(yīng)當(dāng)總是使用絕對路徑引用。
包還提供一個額外的屬性__path__。這是一個目錄列表,里面每一個包含的目錄都有為這個包服務(wù)的__init__.py,你得在其他__init__.py被執(zhí)行前定義哦??梢孕薷倪@個變量,用來影響包含在包里面的模塊和子包。
這個功能并不常用,一般用來擴展包里面的模塊。