Python 套件,常規套件,命名空間套件介紹

閱讀 8:27·字數 2539·發佈 
Youtube 頻道
訂閱 133

本節所講述的內容,並不完全適用於通過類別ModuleType動態建立的表示套件的模組型別物件。

Python 套件

Python 套件是一類特殊的模組,他並不對應同名的py腳本檔案,而是對應同名的資料夾。

如何判斷 Python 模組是否為套件?

在程式碼層面,如果一個模組具有__path__特性,則該模組為 Python 套件。__path__特性可用於指示 Python 套件對應的資料夾路徑。

在 Python 的互動模式中,我們嘗試檢視模組reos__path__特性。從輸出結果可以看出,模組re是套件,模組os不是套件。

Windows
import re
re.__path__
['\\python312.zip\\re']
import os
os.__path__

AttributeError: module 'os' has no attribute '__path__'. Did you mean: '__all__'?
UNIX/Linux/macOS
import re
re.__path__
['/usr/lib/python3.11/re']
import os
os.__path__

AttributeError: module 'os' has no attribute '__path__'. Did you mean: '__all__'?

如何命名 Python 套件?

Python 套件的名稱預設與其對應的資料夾名稱相同,並不需要特意的命名。比如,一個名稱為workers的資料夾,其對應的套件名稱為workers

應該稱呼 Python 模組還是 Python 套件?

由於套件是一種特殊的模組,因此,稱呼某個套件為模組並不算錯誤,比如,re模組。

模組

如果你需要了解 Python 模組,可以檢視Python 模組完整名稱,模組快取介紹一節。

Python 常規套件

Python 常規套件對應的資料夾,擁有一個名為__init__.py的檔案,他相當於模組對應的同名py檔案,包含套件的相關程式碼。

Python 常規套件的儲存形式

在編寫程式碼期間,Python 常規套件儲存為資料夾和資料夾中__init__.py檔案。但編譯後,常規套件的相關程式碼會轉變為位元組碼並儲存在pyc檔案中。

這裏,套件hero對應的資料夾包含__init__.py,因此hero是一個常規套件。

hero/__init__.py
# hero 是一個常規套件
print('我是常規套件 hero!')

Python 命名空間套件

如果套件對應的資料夾未包含名為__init__.py的檔案,則該套件被稱為命名空間套件。

命名空間套件和常規套件之間的區別

事實上,常規套件和命名空間套件都具有命名空間的效果,在不同的常規套件或命名空間套件中,你可以定義名稱相同的內容。至於區別,除了是否包含檔案__init__.py,還有以下幾點。

命名空間套件的__file__特性為None,而常規套件為__init__.py檔案的路徑。命名空間套件的__path__特性為_NamespacePath型別,而常規套件為串列。命名空間套件的__loader__特性為NamespaceLoader型別,而常規套件為SourceFileLoader型別。

Python 模組的 __loader__ 特性

Python 模組的__loader__特性表示用於載入該模組的載入器。

這裏,我們新增一個空的資料夾enemies,他將對應命名空間套件。切換命令列至enemies的上級資料夾,啟動 Python 互動模式並使用import進行匯入操作,然後檢視enemies套件的相關資訊。

Windows
import enemies
enemies.__file__ == None
True
enemies.__path__
_NamespacePath(['\\packages\\enemies'])
enemies.__loader__
<_frozen_importlib_external.NamespaceLoader object at>
UNIX/Linux/macOS
import enemies
enemies.__file__ == None
True
enemies.__path__
_NamespacePath(['/packages/enemies'])
enemies.__loader__
<_frozen_importlib_external.NamespaceLoader object at>

命名空間,有效範圍

要了解什麽是命名空間,可以檢視程式設計教學命名空間,有效範圍介紹一節。

zip 檔案中的 Python 套件

zip檔案中,Python 套件只能以常規套件的形式存在,他們應該具有腳本檔案__init__.py,否則將無法被匯入。

在下面的範例中,壓縮檔案plants.zip含有常規套件flowers,與plants.zip處於同一目錄的腳本檔案my_plants.py,會嘗試匯入zip中的flowers套件。啟動命令列並切換至檔案my_plants.py所在的目錄,執行後可以看到相關的輸出結果。

plants/flowers/__init__.py
# flowers 是一個常規套件
print('我是套件 flowers!')
my_plants.py
# 取得壓縮檔案 plants.zip 的絕對路徑,並新增至模組搜尋路徑
import os
import sys
zip_path = os.path.abspath('plants.zip')
sys.path.append(zip_path)

# 匯入 plants.zip 中的 flowers 套件 import flowers
我是套件 flowers!

如果將plants.zip中的腳本檔案__init__.py刪除,那麽重複上述執行步驟會引發例外狀況ModuleNotFoundError

Python 子模組和子套件

Python 套件對應的資料夾中的py檔案或子資料夾,即為該套件的子模組和子套件,子套件可以是常規套件,也可以是命名空間套件。

Python 模組和套件的執行優先順序

雖然這並不符合規格,但處於同一位置的 Python 模組和套件可以具有相同的名稱。在這種情況下,匯入操作將按照如下優先順序進行,常規套件的優先順序最高,模組次之,命名空間套件的優先順序最低。當同名模組或套件中的一個被匯入後,另一個將被忽略。

在套件school中,存在子套件homework和子模組homework,其中子套件homework是一個常規套件。在腳本檔案my_school.py(與school套件對應的資料夾處於同一目錄)中,運算式import school.homework匯入的是常規套件homework,而不是模組homework

school/homework/__init__.py
print('功課太多了!')
school/homework.py
print('這裏是模組 homework!')
my_school.py
# 匯入套件 school 的子套件 homework,他是一個常規套件
import school.homework
功課太多了!

如果把資料夾homework中的腳本檔案__init__.py刪除,那麽常規套件homework會變為命名空間套件,再次執行my_school.py將匯入模組homework

這裏是模組 homework!

內容分類

程式碼

hero/__init__.py·codebeatme/python-reference·GitHub
plants/flowers/__init__.py·codebeatme/python-reference·GitHub
my_plants.py·codebeatme/python-reference·GitHub
school/homework/__init__.py·codebeatme/python-reference·GitHub
school/homework.py·codebeatme/python-reference·GitHub
my_school.py·codebeatme/python-reference·GitHub