Python 模組完整名稱,模組快取介紹

閱讀 8:01·字數 2408·發佈 
Youtube 頻道
訂閱 133

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

Python 模組的完整名稱

Python 模組的完整名稱,可以讓模組被匯入系統正確的搜尋到,因此,完整名稱一般需要根據 Python 的模組搜尋路徑來確定。

當模組對應的py檔案或pyc位元組碼檔案,或套件對應的資料夾,位於模組搜尋路徑的任意目錄中時,模組或套件的名稱就是其完整名稱。否則,完整名稱應使用.拼接模組或套件所在的父級套件的名稱,這一過程將重複,直至某個父級套件位於模組搜尋路徑的任意目錄。

Python 模組的完整名稱類似於檔案系統中的路徑

在完整名稱中包含父級套件的名稱,是合情合理的,因為 Python 套件具有命名空間的效果。而大部分情況下,Python 套件與資料夾對應,因此,完整名稱的表現方式類似於檔案系統的路徑。

Python 模組的完整名稱可能會發生變化

當 Python 的模組搜尋路徑改變時,模組的完整名稱可能會發生相應的變化。當然,應對這種情況,最好的方式是重新調整模組搜尋路徑,而不是修改程式碼中的完整名稱。

模組搜尋路徑

要取得關於模組搜尋路徑的資訊,你可以檢視Python 模組搜尋路徑介紹,Python 模組搜尋路徑中的目錄有哪些一節。

這裏,模組teacher和模組student位於同一目錄,student通過import陳述式匯入了teacher。開啟命令列執行student.py將是可行的(範例中命令列的目前目錄為student.py所在的資料夾,當然,你可以切換到其他位置),因為student.py所在的目錄會被新增至模組搜尋路徑,模組teacher的完整名稱是其自身。

teacher.py
print('teacher 模組!')
student.py
# 執行 student.py 可以正常匯入 teacher,因為 student.py 所在的目錄將被新增至搜尋路徑
import teacher
Windows
python student.py
teacher 模組!
UNIX/Linux/macOS
python3 student.py
teacher 模組!

調整模組student,為其匯入同一目錄的套件homework,在該套件對應的__init__.py檔案中,我們匯入了套件中的模組english。這裏請註意模組english的完整名稱homework.english,他基於student.py所在的位置。

student.py
# …
# homework 套件也可以被正常匯入
import homework
homework/__init__.py
print('homework 套件!')

# 這裏的完整名稱基於 student.py 所在的目錄 import homework.english
homework/english.py
print('english 模組!')
Windows
python student.py
teacher 模組!
homework 套件!
english 模組!
UNIX/Linux/macOS
python3 student.py
teacher 模組!
homework 套件!
english 模組!

對於完整名稱homework.english,如果我們直接執行homework套件的__init__.py檔案(範例中命令列的目前目錄為__init__.py所在的資料夾,當然,你可以切換到其他位置),那麽將產生一個錯誤。因為模組搜尋路徑已經不再包含student.py所在的目錄,完整名稱homework.english應改為english

Windows
python __init__.py
homework 套件!

ModuleNotFoundError: No module named 'homework'
UNIX/Linux/macOS
python3 __init__.py
homework 套件!

ModuleNotFoundError: No module named 'homework'

Python 模組快取

無論是哪種快取,使用他們的目的在於提高執行效率,以犧牲部分儲存空間為代價,避免大量重複和耗時的工作。Python 的模組快取包含了已經載入的模組或套件,他們儲存在sys模組的modules變數中,該變數是一個字典,字典中的鍵對應了模組的完整名稱,字典中的值對應了表示模組的ModuleType物件。

Python 中的 ModuleType 物件

你可以將ModuleType物件視為模組在程式碼層面的真實實作,一般情況下他們儲存在sys.modules字典中。開發人員可以編寫程式碼,來主動建立一個ModuleType物件並將其加入模組快取。

sys.modules 中的 None 會導致無法匯入相關 Python 模組或套件

如果將字典sys.modules中某個鍵值組的值設定為None,那麽嘗試匯入該鍵值組對應的模組會引發例外狀況ModuleNotFoundError。對於在設定None之前匯入的模組,則可以延續其有效性。

匯入系統

想要取得更多關於匯入系統的資訊,你可以檢視什麽是 Python 匯入系統一節。

這裏模組car定義了類別Car,在腳本檔案cache_none.py中,我們提前將模組car對應的快取設定為None,然後使用import陳述式將其匯入,例外狀況ModuleNotFoundError會被擲回。

car.py
# 一個表示汽車的類別
class Car:
	pass
cache_none.py
import sys
# 模組 car 的完整名稱為 car,這裏提前將其快取設定為 None
sys.modules['car'] = None

# 匯入模組 car 將導致例外狀況 import car
ModuleNotFoundError: import of car halted; None in sys.modules

清除 Python 模組快取

雖然沒有必要,但你可以清空 Python 的模組快取,這將導致下一次的匯入操作需要重新載入相關的模組或套件。

重新匯入的 Python 模組與之前匯入的 Python 模組不同

如果一個模組對應的快取被清除,那麽重新匯入的模組與之前匯入的模組,是兩個不同的ModuleType物件,模組中定義的類別也會有所區別。

在下面的範例中,我們將模組car的快取儲存至變數module1,並建立Car的執行個體car1,之後清除模組的快取重新匯入,建立Car的執行個體car2,對比前後的模組快取和Car物件的型別,會發現他們並不相同。

cache_clear.py
import sys

# 首次匯入模組 car,並建立 Car 物件 import car module1 = sys.modules['car'] car1 = car.Car()
# 清除模組 car 的快取 del sys.modules['car']
# 再次匯入模組 car,並建立 Car 物件 import car module2 = sys.modules['car'] car2 = car.Car()
print(f'module1 == module2 能成立?{module1 == module2}') print(f'car1 與 car2 的型別相同?{type(car1) == type(car2)}')
module1 == module2 能成立?False
car1 與 car2 的型別相同?False

程式碼

teacher.py·codebeatme/python-reference·GitHub
student.py·codebeatme/python-reference·GitHub
homework/__init__.py·codebeatme/python-reference·GitHub
homework/english.py·codebeatme/python-reference·GitHub
car.py·codebeatme/python-reference·GitHub
cache_none.py·codebeatme/python-reference·GitHub
cache_clear.py·codebeatme/python-reference·GitHub