python 模塊加載
本文主要介紹python模塊加載的過程。
module的組成
所有的module都是由對象和對象之間的關系組成。
type和object
python中所有的東西都是對象,分為三類:類型type、類class和實例instance。
三種對象之間的兩種關系:
- is kind of,基類和子類的關系
- is instance of,類和對象的關系
類和對象的關系可以通過內建方法type
來辨別。
python中,任何一個類都是直接或間接繼承自object,而每一個對象都會擁有自己的type類型,可以通過__class__屬性獲得。
運行環境初始化
python首先需要加載多個基礎的module,例如__builtin__,sys等,同時也會完成python類型系統的初始化和異常系統的初始化。
系統module初始化
Python內部維護了一個維護加載到內存的module集合,需要現在集合中查找module是否存在。如果存在直接返回該module對象,否則創建該module對象,並插入到module集合中。創建module后,需要設置module的屬性。
由於python的module集合是一個PyDictObject對象,而PyDictObject對象在Python中是一個可變對象,所以其中維護的元素有可能在運行時被刪除。對於Python的擴展module,例如sys,為了避免再一次初始化同樣的module,python將所有的擴展module通過一個全局的PyDictObject對象來進行備份維護。
啟動虛擬機
python包括兩種運行方式:命令行和腳本文件。
python中的run_mode函數基於AST抽象語法樹 (AST, Abstract Syntax Tree)完成了字節碼的編譯工作,並創建PyCodeObject對象。
python中所有的線程都是共享同樣的builtin名字空間。
模塊的動態加載
import功能包括:
- python運行時的全局module緩存的維護和搜索;
- 解析和搜索module路徑的樹形結構;
- 對不同文件格式的module動態加載機制。
py文件中的import不會影響上一層的命名空間,只會影響各自的命名空間,也就是影響各自module自身維護的那個dict對象。但所有的import操作都會影響全局的module集合,這樣的話只要再一次import該module,python虛擬機只需要將全局module集合中緩存的對象返回。
在module的基礎之上,python提供了package機制(邏輯相關聯的module需要聚合到同一package中)。也就是說通過package機制來管理module,通過module來管理class。
文件件中存在__init__.py文件才能成為package(多個py文件組成的文件夾)。
在加載package下的module時,例如a.b.c,python內部將這個module視為一個樹形結構,c是b的子節點,b是a的子節點。python虛擬機在動態加載時,需要將這個樹形結構分解,然后從左到右依次去sys.modules中查找每一個符號是否存在。如果已經存在,假設存在a,那么在a對應的PyModuleObject對象中保持着__path__路徑信息,此時就可以在a.__path__路徑中搜索b和c了。
del刪除模塊只是把模塊從當前命名空間中刪除,但該module依然存在於module緩存中。
module緩存
python中的全局module集合sys.modules被稱為modules緩存,保證了module的唯一性,每當有import操作都會在該sys.modules查找,如果不存在就會將該module加入到sys.modules中。
如果已經加載的模塊發生改變,那么需要調用reload
函數來重新加載該模塊。需要注意reload函數並不會重新創建該對象,而在在原有對象的基礎上做修改。