Python 模組完整名稱,模組快取介紹
訂閱 480
本節所講述的內容,並不完全適用於通過類別ModuleType動態建立的模組型別物件。
Python 模組的完整名稱
Python 模組的完整名稱,可以讓模組被匯入系統正確的搜尋到,因此,完整名稱一般需要根據模組搜尋路徑來確定。
當模組對應的py檔案或pyc位元組碼檔案,或套件對應的資料夾,位於模組搜尋路徑的任意目錄中時,模組或套件的名稱就是其完整名稱。否則,完整名稱應使用.拼接模組或套件所在的父級套件的名稱,這一過程將重複,直至某個父級套件位於模組搜尋路徑的任意目錄。
模組的完整名稱類似於檔案系統中的路徑
在完整名稱中包含父級套件的名稱,是合情合理的,因為 Python 套件具有命名空間的效果。而大部分情況下,套件與資料夾對應,因此,完整名稱的表現方式類似於檔案系統的路徑。
模組的完整名稱可能會發生變化
當模組搜尋路徑改變時,模組的完整名稱可能會發生相應的變化。當然,應對這種情況,最好的方式是重新調整模組搜尋路徑,而不是修改程式碼中的完整名稱。
模組搜尋路徑
要取得關於模組搜尋路徑的資訊,你可以檢視Python 模組搜尋路徑介紹,模組搜尋路徑中的目錄有哪些一節。
這裏,模組teacher和模組student位於同一目錄,student通過import陳述式匯入了teacher。開啟命令列執行student.py將是可行的(範例中命令列的目前目錄為student.py所在的資料夾,當然,你可以切換到其他位置),因為student.py所在的目錄會被新增至模組搜尋路徑,模組teacher的完整名稱是其自身。
print('teacher 模組!')# 執行 student.py 可以正常匯入 teacher,因為 student.py 所在的目錄將被新增至搜尋路徑
import teacherpython student.py
teacher 模組!python3 student.py
teacher 模組!調整模組student,為其匯入同一目錄的套件homework,在該套件對應的__init__.py檔案中,我們匯入了套件中的模組english。這裏請註意模組english的完整名稱homework.english,他基於student.py所在的位置。
# …
# homework 套件也可以被正常匯入
import homeworkprint('homework 套件!')
# 這裏的完整名稱基於 student.py 所在的目錄
import homework.englishprint('english 模組!')python student.py
teacher 模組!
homework 套件!
english 模組!python3 student.py
teacher 模組!
homework 套件!
english 模組!對於完整名稱homework.english,如果我們直接執行homework套件的__init__.py檔案(範例中命令列的目前目錄為__init__.py所在的資料夾,當然,你可以切換到其他位置),那麽將產生一個錯誤。因為模組搜尋路徑已經不再包含student.py所在的目錄,完整名稱homework.english應改為english。
python __init__.py
homework 套件!
…
ModuleNotFoundError: No module named 'homework'python3 __init__.py
homework 套件!
…
ModuleNotFoundError: No module named 'homework'Python 模組快取
無論是哪種快取,使用他們的目的在於提高執行效率,以犧牲部分儲存空間為代價,避免大量重複和耗時的工作。Python 的模組快取包含了已經載入的模組或套件,他們儲存在sys模組的modules變數中,該變數是一個字典,字典中的鍵對應了模組的完整名稱,字典中的值對應了表示模組的ModuleType物件。
ModuleType 物件
你可以將ModuleType物件視為模組在程式碼層面的真實實作,一般情況下他們儲存在sys.modules字典中。開發人員可以編寫程式碼,來主動建立一個ModuleType物件並將其加入模組快取。
sys.modules 中的 None 會導致無法匯入相關模組或套件
如果將字典sys.modules中某個鍵值組的值設定為None,那麽嘗試匯入該鍵值組對應的模組會引發例外狀況ModuleNotFoundError。對於在設定None之前匯入的模組,則可以延續其有效性。
匯入系統
想要取得更多關於匯入系統的資訊,你可以檢視什麽是 Python 匯入系統一節。
這裏模組car定義了類別Car,在腳本檔案cache_none.py中,我們提前將模組car對應的快取設定為None,然後使用import陳述式將其匯入,例外狀況ModuleNotFoundError會被擲回。
# 一個表示汽車的類別
class Car:
passimport sys
# 模組 car 的完整名稱為 car,這裏提前將其快取設定為 None
sys.modules['car'] = None
# 匯入模組 car 將導致例外狀況
import carModuleNotFoundError: import of car halted; None in sys.modules清除 Python 模組快取
雖然沒有必要,但你可以清空模組快取,這將導致下一次的匯入操作需要重新載入相關的模組或套件。
重新匯入的模組與之前匯入的模組不同
如果一個模組對應的快取被清除,那麽重新匯入的模組與之前匯入的模組,是兩個不同的ModuleType物件,模組中定義的類別也會有所區別。
在下面的範例中,我們將模組car的快取儲存至變數module1,並建立Car的執行個體car1,之後清除模組的快取重新匯入,建立Car的執行個體car2,對比前後的模組快取和Car物件的型別,會發現他們並不相同。
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