Python 模組完整名稱,模組快取介紹
本節所講述的內容,並不完全適用於通過類別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
的完整名稱是其自身。
print('teacher 模組!')
# 執行 student.py 可以正常匯入 teacher,因為 student.py 所在的目錄將被新增至搜尋路徑
import teacher
python student.py
teacher 模組!
python3 student.py
teacher 模組!
調整模組student
,為其匯入同一目錄的套件homework
,在該套件對應的__init__.py
檔案中,我們匯入了套件中的模組english
。這裏請註意模組english
的完整名稱homework.english
,他基於student.py
所在的位置。
# …
# homework 套件也可以被正常匯入
import homework
print('homework 套件!')
# 這裏的完整名稱基於 student.py 所在的目錄
import homework.english
print('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
物件。
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
會被擲回。
# 一個表示汽車的類別
class Car:
pass
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
物件的型別,會發現他們並不相同。
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