包,Package,是一種Python模組的集合,從檔案組織形式上看,包就是一個資料夾,裡面放著各種模組(.py檔案),也可以有子資料夾(子包)。包名構建了一個Python模組的名稱空間。比如,模組名A.B
表示A
包中名為B
的子模組。這種使用加點的模組名可以讓你寫的軟體包裡面的模組名稱和其它軟體包裡面的模組名稱一樣,但又不相互衝突。
舉個例子,我們要設計一個處理圖片的模組集合(一個包)。我們知道,圖片有多種不同的檔案格式,一般它們以不同的副檔名來識別,比如.jpg
,.png
,.gif
等等。為了讀寫不同格式的圖片,你需要對每一種格式建立一個對應的模組進行處理,為了支援更多的圖片格式,你就要增加更多對應的模組。對於圖片你可能還有更多的處理,比如,改變色彩,裁剪,旋轉等等,為了實現這些功能,你又要寫更多的模組。這樣下來,你的包的結構以檔案系統的形式表示如下:
image # 頂級包
├── __init__.py # 初始化image包
├── formats # 圖片格式的子包
│ ├── gif_read.py
│ ├── gif_write.py
│ ├── __init__.py
│ ├── jpg_read.py
│ ├── jpg_write.py
│ ├── png_read.py
│ └── png_write.py
└── process # 圖片處理的子包
├── colors.py
├── crop.py
├── __init__.py
└── rotate.py
為了讓目錄成為Python的包,目錄中必須含有一個__init__.py
檔案,它可以是空檔案但不能不存在。這樣做的目的是為了仿照具有通用名稱的目錄無意中隱藏了在模組搜尋路徑排在後面的有效模組。比如,你當前目錄下有個time
目錄是放程式資源的,它裡面沒有__init__.py
檔案就是一個普通的目錄。如果Python不要求包目錄下必須含有__init__.py
檔案,它就會隱藏Python系統的time模組。
__all__變數
前面說了,包的目錄中必須包含一個__init__.py
檔案,它可以是空檔案,也可以寫包初始化相關的程式碼,或者定義__all__
變數。
__all__
變數是一個列表,它列舉了這個包包含的子模組的名稱。當from package import *
語句執行時,會把這個模組名稱列表裡面的模組名稱匯入。所以說__all__
是一個包的顯示索引。如果你覺得從包中匯入*
的操作沒必要被使用,也可以不定義__all__
這個變數。
例如,檔案image/process/init.py可以包含以下程式碼:
__all__ = ['colors', 'crop', 'rotate']
定義了__all__
之後,from image.process import *
就會把colors
,crop
,rotate
匯入到當前名稱空間。
實際寫程式碼的實踐中,import *
的做法是嚴格被禁止的,它容易造成包中模組名與當前名稱空間的名稱衝突。
更推薦的方法是from package import submodule
或from package import submodule as alias_for_submodule
。當然,如果兩個包中有同名的submodule,就不能同時使用from package import submodule
,但可以取個別名。
匯入Python包或Python子模組
匯入包的方法和匯入模組的方法一樣:
import image
在程式中引用colors
子模組時:
image.process.colors(...)
接下來,看看我們如何匯入一個包中某單個模組:
import image.process.colors
這樣就載入了子模組image.process.colors
,在程式中使用時必須使用它的全名,而不是簡單的colors
。
如果想使用colors
這個名字,就用這種匯入語句:
from image.process import colors
Python子包參考
當包含有子包時(與例子中的image包類似),我們可以使用絕對匯入來引用兄弟包的子模組。比如,如果模組 image.process.crop 需要使用 image.formats 包中的 jpg_read 模組時,它可以使用 from image.formats import jpg_read
。
我們也可以使用 from module import name
的形式相對匯入。這種匯入使用前導點.
來指示相對匯入中涉及的當前包
和父包
。比如,在 crop 模組中,你可以使用:
from . import colors
from .. import formats
from ..formats import jpg_read
請主要,相對匯入是基於當前模組的名字進行匯入的。由於主模組(即被python 執行的那個.py檔案)的名稱總是"__main__"
,因此用作Python應用程式的主模組的模組必須用絕對匯入。也就是說被執行的主程式裡面不能包含相對匯入。這一點很重要,切記!
我的公眾號:猿人學 Python 上會分享更多心得體會,敬請關注。
***版權申明:若沒有特殊說明,文章皆是猿人學 yuanrenxue.com 原創,沒有猿人學授權,請勿以任何形式轉載。***