importlib
— import
的實現¶
3.1 版本新增。
原始碼: Lib/importlib/__init__.py
簡介¶
importlib
包的目的是三重的。
一是提供 Python 原始碼中 import
語句(以及擴充套件的 __import__()
函式)的實現。這提供了可移植到任何 Python 直譯器的 import
實現。這也提供了一個比用 Python 以外的程式語言實現的更容易理解的實現。
二是,實現 import
的元件在此包中公開,使使用者更容易建立自己的自定義物件(統稱為 匯入器)參與匯入過程。
三是,該軟體包包含用於管理 Python 包的其他功能模組
importlib.metadata
提供對第三方發行版元資料的訪問。importlib.resources
提供了從 Python 包訪問非程式碼“資源”的例程。
另請參閱
- import 語句
關於
import
語句的語言參考。- 包規範
包的原始規範。 自編寫本文件以來,某些語義已更改(例如,根據
sys.modules
中的None
重定向)。__import__()
函式import
語句是此函式的語法糖。- sys.path 模組搜尋路徑的初始化
sys.path
的初始化。- PEP 235
在不區分大小寫的平臺上匯入
- PEP 263
定義 Python 原始碼編碼
- PEP 302
新的匯入鉤子
- PEP 328
匯入:多行和絕對/相對
- PEP 366
主模組顯式相對匯入
- PEP 420
隱式名稱空間包
- PEP 451
匯入系統的 ModuleSpec 型別
- PEP 488
消除 PYO 檔案
- PEP 489
多階段擴充套件模組初始化
- PEP 552
確定性的 pycs
- PEP 3120
使用 UTF-8 作為預設原始碼編碼
- PEP 3147
PYC 儲存庫目錄
函式¶
- importlib.__import__(name, globals=None, locals=None, fromlist=(), level=0)¶
內建
__import__()
函式的實現。注意
模組的程式化匯入應使用
import_module()
而不是此函式。
- importlib.import_module(name, package=None)¶
匯入一個模組。name 引數指定要以絕對或相對方式匯入的模組(例如,
pkg.mod
或..mod
)。如果名稱以相對方式指定,則 package 引數必須設定為要用作解析包名錨點的包的名稱(例如,import_module('..mod', 'pkg.subpkg')
將匯入pkg.mod
)。import_module()
函式充當importlib.__import__()
的簡化包裝器。這意味著該函式的所有語義都源自importlib.__import__()
。這兩個函式之間最重要的區別是import_module()
返回指定的包或模組(例如,pkg.mod
),而__import__()
返回頂層包或模組(例如,pkg
)。如果您正在動態匯入自直譯器開始執行以來建立的模組(例如,建立了一個 Python 原始檔),您可能需要呼叫
invalidate_caches()
,以便匯入系統注意到新模組。在 3.3 版本中更改: 父包會自動匯入。
- importlib.invalidate_caches()¶
使儲存在
sys.meta_path
中的查詢器的內部快取失效。如果查詢器實現了invalidate_caches()
,則將呼叫它來執行失效操作。如果在程式執行時建立/安裝了任何模組,則應呼叫此函式以確保所有查詢器都會注意到新模組的存在。在 3.3 版本中新增。
在 3.10 版本中更改: 在同一名稱空間已被匯入後,在不同的
sys.path
位置建立/安裝的名稱空間包也會被注意到。
- importlib.reload(module)¶
重新載入之前匯入的 module。引數必須是模組物件,因此它必須之前已成功匯入。如果您使用外部編輯器編輯了模組原始檔,並希望在不離開 Python 直譯器的情況下試用新版本,這將非常有用。返回值是模組物件(如果重新匯入導致將不同的物件放入
sys.modules
中,則該物件可能會有所不同)。當
reload()
執行時Python 模組的程式碼會被重新編譯,並且會重新執行模組級別的程式碼,從而透過重用最初載入模組的 載入器 來定義一組新的物件,這些物件會繫結到模組字典中的名稱。擴充套件模組的
init
函式不會被第二次呼叫。與 Python 中的所有其他物件一樣,舊物件僅在其引用計數降至零後才會被回收。
模組名稱空間中的名稱會被更新以指向任何新的或更改的物件。
對舊物件的其他引用(例如,模組外部的名稱)不會重新繫結以引用新物件,如果需要,必須在它們出現的每個名稱空間中更新它們。
還有一些其他注意事項
重新載入模組時,它的字典(包含模組的全域性變數)會被保留。名稱的重新定義會覆蓋舊的定義,所以這通常不是問題。如果模組的新版本沒有定義舊版本定義的名稱,則舊的定義仍然存在。如果模組維護一個全域性表或物件快取,則可以使用此功能 — 透過一個
try
語句,它可以測試該表的存在,並在需要時跳過其初始化try: cache except NameError: cache = {}
重新載入內建模組或動態載入的模組通常不是很有用。不建議重新載入
sys
、__main__
、builtins
和其他關鍵模組。在許多情況下,擴充套件模組的設計目的不是被初始化多次,並且在重新載入時可能會以任意方式失敗。如果一個模組使用
from
…import
… 從另一個模組匯入物件,則為其他模組呼叫reload()
不會重新定義從中匯入的物件 — 一種解決方法是重新執行from
語句,另一種方法是使用import
和限定名稱 (module.name) 來代替。如果一個模組例項化了一個類的例項,則重新載入定義該類的模組不會影響例項的方法定義 — 它們將繼續使用舊的類定義。派生類也是如此。
在 3.4 版本中新增。
在 3.7 版本中更改: 當重新載入的模組缺少
ModuleSpec
時,會引發ModuleNotFoundError
。
importlib.abc
– 與匯入相關的抽象基類¶
原始碼: Lib/importlib/abc.py
importlib.abc
模組包含 import
使用的所有核心抽象基類。還提供了一些核心抽象基類的子類,以幫助實現核心 ABC。
ABC 層次結構
object
+-- MetaPathFinder
+-- PathEntryFinder
+-- Loader
+-- ResourceLoader --------+
+-- InspectLoader |
+-- ExecutionLoader --+
+-- FileLoader
+-- SourceLoader
- class importlib.abc.MetaPathFinder¶
表示 元路徑查詢器 的抽象基類。
在 3.3 版本中新增。
在 3.10 版本中更改: 不再是
Finder
的子類。- find_spec(fullname, path, target=None)¶
一個用於查詢指定模組的 spec 的抽象方法。如果這是一個頂層匯入,path 將為
None
。否則,這是一個搜尋子包或模組的操作,並且 path 將是父包的__path__
的值。如果找不到 spec,則返回None
。當傳入時,target
是一個模組物件,查詢器可以使用它來更明智地猜測要返回哪個 spec。importlib.util.spec_from_loader()
對於實現具體的MetaPathFinders
可能很有用。在 3.4 版本中新增。
- invalidate_caches()¶
一個可選的方法,當被呼叫時,應該使查詢器使用的任何內部快取失效。當使
sys.meta_path
上所有查詢器的快取失效時,由importlib.invalidate_caches()
使用。在 3.4 版本中更改: 呼叫時返回
None
而不是NotImplemented
。
- class importlib.abc.PathEntryFinder¶
一個表示 路徑入口查詢器 的抽象基類。雖然它與
MetaPathFinder
有一些相似之處,但PathEntryFinder
僅用於importlib.machinery.PathFinder
提供的基於路徑的匯入子系統中。在 3.3 版本中新增。
在 3.10 版本中更改: 不再是
Finder
的子類。- find_spec(fullname, target=None)¶
一個用於查詢指定模組的 spec 的抽象方法。查詢器將僅在分配給它的 路徑入口 中搜索模組。如果找不到 spec,則返回
None
。當傳入時,target
是一個模組物件,查詢器可以使用它來更明智地猜測要返回哪個 spec。importlib.util.spec_from_loader()
對於實現具體的PathEntryFinders
可能很有用。在 3.4 版本中新增。
- invalidate_caches()¶
一個可選的方法,當被呼叫時,應該使查詢器使用的任何內部快取失效。當使所有快取的查詢器的快取失效時,由
importlib.machinery.PathFinder.invalidate_caches()
使用。
- class importlib.abc.Loader¶
一個 載入器 的抽象基類。有關載入器的確切定義,請參閱 PEP 302。
希望支援資源讀取的載入器應實現
importlib.resources.abc.ResourceReader
指定的get_resource_reader()
方法。在 3.7 版本中更改: 引入了可選的
get_resource_reader()
方法。- create_module(spec)¶
一個返回匯入模組時要使用的模組物件的方法。此方法可以返回
None
,表示應進行預設的模組建立語義。在 3.4 版本中新增。
在 3.6 版本中更改: 當定義了
exec_module()
時,此方法不再是可選的。
- exec_module(module)¶
一個抽象方法,當匯入或重新載入模組時,在模組自己的名稱空間中執行模組。當呼叫
exec_module()
時,模組應該已經初始化。當此方法存在時,必須定義create_module()
。在 3.4 版本中新增。
在 3.6 版本中更改: 還必須定義
create_module()
。
- load_module(fullname)¶
一個用於載入模組的傳統方法。如果無法載入模組,則會引發
ImportError
,否則返回已載入的模組。如果請求的模組已經存在於
sys.modules
中,則應使用該模組並重新載入。否則,載入器應建立一個新模組,並在任何載入開始之前將其插入到sys.modules
中,以防止從匯入中發生遞迴。如果載入器插入了一個模組並且載入失敗,則載入器必須從sys.modules
中刪除它;在載入器開始執行之前已經在sys.modules
中的模組應該保持不變。載入器應在模組上設定多個屬性(請注意,某些屬性可以在重新載入模組時更改)
module.__cached__
(已棄用)module.__package__
(已棄用)module.__loader__
(已棄用)
當
exec_module()
可用時,將提供向後相容的功能。在 3.4 版本中更改: 當呼叫時,引發
ImportError
而不是NotImplementedError
。當exec_module()
可用時,提供功能。3.4 版本已棄用: 載入模組的推薦 API 是
exec_module()
(和create_module()
)。載入器應該實現它而不是load_module()
。當實現了exec_module()
時,匯入機制會處理load_module()
的所有其他職責。
- class importlib.abc.ResourceLoader¶
一個用於載入器的抽象基類,它實現了可選的 PEP 302 協議,用於從儲存後端載入任意資源。
3.7 版本已棄用: 此 ABC 已被棄用,建議透過
importlib.resources.abc.ResourceReader
支援資源載入。
- class importlib.abc.InspectLoader¶
一個用於載入器的抽象基類,它實現了可選的 PEP 302 協議,用於檢查模組的載入器。
- get_code(fullname)¶
返回模組的程式碼物件,如果模組沒有程式碼物件(例如,對於內建模組),則返回
None
。如果載入器無法找到請求的模組,則引發ImportError
。注意
雖然該方法具有預設實現,但建議在可能的情況下為了提高效能而重寫它。
在 3.4 版本中變更: 不再是抽象方法,並提供了具體實現。
- abstractmethod get_source(fullname)¶
一個抽象方法,用於返回模組的原始碼。它以文字字串的形式返回,使用 通用換行符,將所有已識別的行分隔符轉換為
'\n'
字元。如果沒有可用的原始碼(例如,內建模組),則返回None
。如果載入器無法找到指定的模組,則引發ImportError
。在 3.4 版本中變更: 引發
ImportError
而不是NotImplementedError
。
- is_package(fullname)¶
一個可選方法,如果模組是包,則返回 true 值,否則返回 false 值。如果載入器找不到模組,則引發
ImportError
。在 3.4 版本中變更: 引發
ImportError
而不是NotImplementedError
。
- static source_to_code(data, path='<string>')¶
從 Python 原始碼建立程式碼物件。
data 引數可以是
compile()
函式支援的任何內容(即字串或位元組)。path 引數應該是原始碼的“路徑”,這可以是一個抽象概念(例如,zip 檔案中的位置)。使用後續的程式碼物件,可以透過執行
exec(code, module.__dict__)
在模組中執行它。在 3.4 版本中新增。
在 3.5 版本中變更: 使該方法成為靜態方法。
- exec_module(module)¶
Loader.exec_module()
的實現。在 3.4 版本中新增。
- load_module(fullname)¶
Loader.load_module()
的實現。3.4 版本已棄用: 請改用
exec_module()
。
- class importlib.abc.ExecutionLoader¶
一個繼承自
InspectLoader
的抽象基類,當實現時,有助於將模組作為指令碼執行。該 ABC 表示可選的 PEP 302 協議。- abstractmethod get_filename(fullname)¶
一個抽象方法,用於返回指定模組的
__file__
的值。如果沒有可用的路徑,則引發ImportError
。如果有原始碼可用,則無論是否使用位元組碼載入模組,該方法都應返回原始碼檔案的路徑。
在 3.4 版本中變更: 引發
ImportError
而不是NotImplementedError
。
- class importlib.abc.FileLoader(fullname, path)¶
一個繼承自
ResourceLoader
和ExecutionLoader
的抽象基類,提供了ResourceLoader.get_data()
和ExecutionLoader.get_filename()
的具體實現。fullname 引數是載入器要處理的模組的完整解析名稱。path 引數是模組檔案的路徑。
在 3.3 版本中新增。
- name¶
載入器可以處理的模組的名稱。
- path¶
模組檔案的路徑。
- load_module(fullname)¶
呼叫父類的
load_module()
。3.4 版本起已棄用: 請改用
Loader.exec_module()
。
- abstractmethod get_data(path)¶
以二進位制檔案形式讀取 path 並返回其中的位元組。
- class importlib.abc.SourceLoader¶
用於實現原始碼(和可選的位元組碼)檔案載入的抽象基類。該類同時繼承自
ResourceLoader
和ExecutionLoader
,要求實現以下方法:ExecutionLoader.get_filename()
應該只返回原始碼檔案的路徑;不支援無原始碼載入。
此類定義的抽象方法用於新增可選的位元組碼檔案支援。不實現這些可選方法(或導致它們引發
NotImplementedError
)會導致載入器只能處理原始碼。實現這些方法允許載入器處理原始碼和位元組碼檔案;它不允許只提供位元組碼的無原始碼載入。位元組碼檔案是一種最佳化,透過刪除 Python 編譯器的解析步驟來加快載入速度,因此不會公開特定於位元組碼的 API。- path_stats(path)¶
可選的抽象方法,返回一個包含指定路徑元資料的
dict
。支援的字典鍵有:'mtime'
(必需):表示原始碼修改時間的整數或浮點數;'size'
(可選):原始碼的大小(以位元組為單位)。
字典中的任何其他鍵都會被忽略,以便將來進行擴充套件。如果無法處理路徑,則會引發
OSError
。在 3.3 版本中新增。
在 3.4 版本中更改: 引發
OSError
而不是NotImplementedError
。
- path_mtime(path)¶
可選的抽象方法,返回指定路徑的修改時間。
3.3 版本起已棄用: 此方法已棄用,推薦使用
path_stats()
。您不必實現它,但它仍然可用作相容性用途。如果無法處理路徑,則會引發OSError
。在 3.4 版本中更改: 引發
OSError
而不是NotImplementedError
。
- set_data(path, data)¶
可選的抽象方法,將指定的位元組寫入檔案路徑。任何不存在的中間目錄都應自動建立。
當由於路徑是隻讀的(
errno.EACCES
/PermissionError
)而導致寫入路徑失敗時,不要傳播異常。在 3.4 版本中更改: 呼叫時不再引發
NotImplementedError
。
- get_code(fullname)¶
InspectLoader.get_code()
的具體實現。
- exec_module(module)¶
Loader.exec_module()
的具體實現。在 3.4 版本中新增。
- load_module(fullname)¶
Loader.load_module()
的具體實現。3.4 版本起已棄用: 請改用
exec_module()
。
- get_source(fullname)¶
InspectLoader.get_source()
的具體實現。
- is_package(fullname)¶
InspectLoader.is_package()
的具體實現。如果模組的檔案路徑(由ExecutionLoader.get_filename()
提供)是一個名為__init__
的檔案(當刪除副檔名時),並且模組名稱本身不以__init__
結尾,則該模組被確定為包。
- class importlib.abc.ResourceReader¶
已被 TraversableResources 取代
一個 抽象基類,用於提供讀取資源的能力。
從此 ABC 的角度來看,資源 是一個隨包一起提供的二進位制工件。通常,這類似於位於包的
__init__.py
檔案旁的資料檔案。此類旨在幫助抽象出對此類資料檔案的訪問,以便無論包及其資料檔案是儲存在 zip 檔案中還是檔案系統中,都無關緊要。對於此類的方法,resource 引數應為一個 path-like object,它在概念上僅表示一個檔名。這意味著 resource 引數中不應包含任何子目錄路徑。這是因為讀取器所屬的包的位置充當“目錄”。因此,目錄和檔名的隱喻分別是包和資源。這也是為什麼此類的例項應該直接關聯到特定的包(而不是可能表示多個包或模組)。
希望支援資源讀取的載入器應提供一個名為
get_resource_reader(fullname)
的方法,該方法返回一個實現此 ABC 介面的物件。如果 fullname 指定的模組不是包,則此方法應返回None
。僅當指定的模組是包時,才應返回與此 ABC 相容的物件。3.7 版本新增。
3.12 版本起已棄用, 將在 3.14 版本中移除: 請改用
importlib.resources.abc.TraversableResources
。- abstractmethod open_resource(resource)¶
返回一個已開啟的、用於二進位制讀取 resource 的類檔案物件。
如果找不到資源,則會引發
FileNotFoundError
。
- abstractmethod resource_path(resource)¶
返回 resource 的檔案系統路徑。
如果資源在檔案系統上不存在,則引發
FileNotFoundError
。
- abstractmethod is_resource(name)¶
如果命名的 name 被認為是資源,則返回
True
。 如果 name 不存在,則會引發FileNotFoundError
。
- abstractmethod contents()¶
返回一個包含包內容的字串的可迭代物件。 請注意,迭代器返回的所有名稱不一定是實際的資源,例如,返回
is_resource()
將返回 false 的名稱是可以接受的。允許返回非資源名稱是為了允許在預先知道包及其資源的儲存方式的情況下,非資源名稱會有用的情況。 例如,允許返回子目錄名稱,這樣當知道包和資源儲存在檔案系統上時,可以直接使用這些子目錄名稱。
抽象方法返回一個不包含任何項的可迭代物件。
- class importlib.abc.Traversable¶
具有
pathlib.Path
方法子集的物件,適用於遍歷目錄和開啟檔案。對於檔案系統上物件的表示,請使用
importlib.resources.as_file()
。3.9 版本新增。
3.12 版本起已棄用, 將在 3.14 版本中移除: 請改用
importlib.resources.abc.Traversable
。- name¶
抽象。此物件的基本名稱,不包含任何父引用。
- abstractmethod iterdir()¶
在
self
中生成Traversable
物件。
- abstractmethod is_dir()¶
如果
self
是目錄,則返回True
。
- abstractmethod is_file()¶
如果
self
是檔案,則返回True
。
- abstractmethod joinpath(child)¶
返回
self
中的 Traversable 子項。
- abstractmethod __truediv__(child)¶
返回
self
中的Traversable
子項。
- abstractmethod open(mode='r', *args, **kwargs)¶
mode 可以是 ‘r’ 或 ‘rb’,分別以文字或二進位制模式開啟。返回適合讀取的控制代碼(與
pathlib.Path.open
相同)。當以文字模式開啟時,接受編碼引數,如
io.TextIOWrapper
接受的引數。
- read_bytes()¶
以位元組形式讀取
self
的內容。
- read_text(encoding=None)¶
以文字形式讀取
self
的內容。
- class importlib.abc.TraversableResources¶
用於資源讀取器的抽象基類,能夠服務於
importlib.resources.files()
介面。 子類importlib.resources.abc.ResourceReader
並提供importlib.resources.abc.ResourceReader
抽象方法的具體實現。因此,任何提供importlib.abc.TraversableResources
的載入器也提供 ResourceReader。希望支援資源讀取的載入器應實現此介面。
3.9 版本新增。
3.12 版本起已棄用, 將在 3.14 版本中移除: 請改用
importlib.resources.abc.TraversableResources
。- abstractmethod files()¶
返回已載入包的
importlib.resources.abc.Traversable
物件。
importlib.machinery
– 匯入器和路徑鉤子¶
原始碼: Lib/importlib/machinery.py
此模組包含幫助 import
查詢和載入模組的各種物件。
- importlib.machinery.SOURCE_SUFFIXES¶
一個字串列表,表示源模組的可識別檔案字尾。
在 3.3 版本中新增。
- importlib.machinery.DEBUG_BYTECODE_SUFFIXES¶
一個字串列表,表示非最佳化位元組碼模組的檔案字尾。
在 3.3 版本中新增。
3.5 版本起已棄用: 請改用
BYTECODE_SUFFIXES
。
- importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES¶
一個字串列表,表示最佳化位元組碼模組的檔案字尾。
在 3.3 版本中新增。
3.5 版本起已棄用: 請改用
BYTECODE_SUFFIXES
。
- importlib.machinery.BYTECODE_SUFFIXES¶
一個字串列表,表示位元組碼模組的可識別檔案字尾(包括前導點)。
在 3.3 版本中新增。
在 3.5 版本中變更: 該值不再依賴於
__debug__
。
- importlib.machinery.EXTENSION_SUFFIXES¶
一個字串列表,表示擴充套件模組的可識別檔案字尾。
在 3.3 版本中新增。
- importlib.machinery.all_suffixes()¶
返回一個字串組合列表,表示標準匯入機制識別的所有模組的檔案字尾。這對於只需要知道檔案系統路徑是否可能指向模組而不需要任何模組型別詳細資訊的程式碼很有用(例如,
inspect.getmodulename()
)。在 3.3 版本中新增。
- class importlib.machinery.BuiltinImporter¶
內建模組的匯入器。所有已知的內建模組都列在
sys.builtin_module_names
中。此類實現了importlib.abc.MetaPathFinder
和importlib.abc.InspectLoader
ABC。此類僅定義類方法,以減輕例項化的需要。
在 3.5 版本中更改: 作為 PEP 489 的一部分,內建匯入器現在實現了
Loader.create_module()
和Loader.exec_module()
- class importlib.machinery.FrozenImporter¶
凍結模組的匯入器。此類實現了
importlib.abc.MetaPathFinder
和importlib.abc.InspectLoader
ABC。此類僅定義類方法,以減輕例項化的需要。
在 3.4 版本中更改: 增加了
create_module()
和exec_module()
方法。
- class importlib.machinery.WindowsRegistryFinder¶
在 Windows 登錄檔中宣告的模組的查詢器。此類實現了
importlib.abc.MetaPathFinder
ABC。此類僅定義類方法,以減輕例項化的需要。
在 3.3 版本中新增。
自 3.6 版本起已棄用: 請改用
site
配置。Python 的未來版本可能預設不啟用此查詢器。
- class importlib.machinery.PathFinder¶
查詢器,用於
sys.path
和包__path__
屬性。此類實現了importlib.abc.MetaPathFinder
ABC。此類僅定義類方法,以減輕例項化的需要。
- classmethod find_spec(fullname, path=None, target=None)¶
嘗試在
sys.path
上或如果已定義,則在 path 上查詢由 fullname 指定的模組的規範的類方法。對於搜尋的每個路徑條目,都會檢查sys.path_importer_cache
。如果找到非假物件,則將其用作路徑條目查詢器,以查詢正在搜尋的模組。如果在sys.path_importer_cache
中找不到任何條目,則會搜尋sys.path_hooks
,以查詢路徑條目的查詢器,如果找到,則將其與正在查詢的模組一起儲存在sys.path_importer_cache
中。如果始終找不到查詢器,則None
會同時儲存在快取中並返回。在 3.4 版本中新增。
在 3.5 版本中更改: 如果當前工作目錄(用空字串表示)不再有效,則會返回
None
,但在sys.path_importer_cache
中不快取任何值。
- classmethod invalidate_caches()¶
對
sys.path_importer_cache
中儲存的所有定義了此方法的查詢器呼叫importlib.abc.PathEntryFinder.invalidate_caches()
。否則,將刪除sys.path_importer_cache
中設定為None
的條目。在 3.7 版本中更改: 刪除
sys.path_importer_cache
中None
的條目。
在 3.4 版本中更改: 對於
''
(即空字串),使用當前工作目錄呼叫sys.path_hooks
中的物件。
- class importlib.machinery.FileFinder(path, *loader_details)¶
importlib.abc.PathEntryFinder
的具體實現,它會快取檔案系統的結果。path 引數是查詢器負責搜尋的目錄。
loader_details 引數是可變數量的 2 項元組,每個元組都包含一個載入器和載入器識別的檔案字尾序列。 載入器應為可呼叫物件,接受模組的名稱和找到的檔案路徑兩個引數。
查詢器會在必要時快取目錄內容,為每個模組搜尋呼叫 stat,以驗證快取未過時。由於快取陳舊性依賴於作業系統檔案系統狀態資訊的粒度,因此存在搜尋模組、建立新檔案,然後搜尋新檔案所代表的模組的潛在競爭條件。如果操作發生得足夠快以適應 stat 呼叫的粒度,則模組搜尋將失敗。為了防止這種情況發生,當動態建立模組時,請確保呼叫
importlib.invalidate_caches()
。在 3.3 版本中新增。
- path¶
查詢器將在其中搜索的路徑。
- invalidate_caches()¶
清除內部快取。
- classmethod path_hook(*loader_details)¶
一個類方法,返回一個閉包,用於
sys.path_hooks
。FileFinder
的例項由閉包返回,該例項直接使用傳遞給閉包的 path 引數,並間接使用 loader_details 引數。如果閉包的引數不是一個已存在的目錄,則會引發
ImportError
異常。
- class importlib.machinery.SourceFileLoader(fullname, path)¶
透過繼承
importlib.abc.FileLoader
並提供其他方法的一些具體實現,來實現importlib.abc.SourceLoader
的具體實現。在 3.3 版本中新增。
- name¶
此載入器將處理的模組的名稱。
- path¶
原始檔的路徑。
- path_stats(path)¶
- set_data(path, data)¶
- load_module(name=None)¶
importlib.abc.Loader.load_module()
的具體實現,其中指定要載入的模組的名稱是可選的。3.6 版本後已棄用: 請改用
importlib.abc.Loader.exec_module()
。
- class importlib.machinery.SourcelessFileLoader(fullname, path)¶
importlib.abc.FileLoader
的具體實現,可以匯入位元組碼檔案(即不存在原始碼檔案)。請注意,直接使用位元組碼檔案(而不是原始碼檔案)會阻止您的模組被所有 Python 實現或更改位元組碼格式的新 Python 版本所使用。
在 3.3 版本中新增。
- name¶
載入器將處理的模組的名稱。
- path¶
位元組碼檔案的路徑。
- get_source(fullname)¶
當使用此載入器時,由於位元組碼檔案沒有原始碼,因此返回
None
。
- load_module(name=None)¶
importlib.abc.Loader.load_module()
的具體實現,其中指定要載入的模組的名稱是可選的。3.6 版本後已棄用: 請改用
importlib.abc.Loader.exec_module()
。
- class importlib.machinery.ExtensionFileLoader(fullname, path)¶
擴充套件模組的
importlib.abc.ExecutionLoader
的具體實現。fullname 引數指定載入器要支援的模組的名稱。path 引數是擴充套件模組檔案的路徑。
請注意,預設情況下,如果擴充套件模組沒有實現多階段初始化(請參閱 PEP 489),即使它在其他情況下可以成功匯入,在子直譯器中匯入擴充套件模組也會失敗。
在 3.3 版本中新增。
在 3.12 版本中變更: 現在在子直譯器中使用需要多階段初始化。
- name¶
載入器支援的模組的名稱。
- path¶
擴充套件模組的路徑。
- is_package(fullname)¶
如果檔案路徑指向包的
__init__
模組,則基於EXTENSION_SUFFIXES
返回True
。
- get_code(fullname)¶
由於擴充套件模組缺少程式碼物件,因此返回
None
。
- get_source(fullname)¶
由於擴充套件模組沒有原始碼,因此返回
None
。
- class importlib.machinery.NamespaceLoader(name, path, path_finder)¶
名稱空間包的
importlib.abc.InspectLoader
的具體實現。這是私有類的別名,僅為了檢查名稱空間包上的__loader__
屬性而公開。>>> from importlib.machinery import NamespaceLoader >>> import my_namespace >>> isinstance(my_namespace.__loader__, NamespaceLoader) True >>> import importlib.abc >>> isinstance(my_namespace.__loader__, importlib.abc.Loader) True
3.11 版本新增。
- class importlib.machinery.ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None)¶
模組的匯入系統相關狀態的規範。這通常作為模組的
__spec__
屬性公開。 許多這些屬性也直接在模組上可用:例如,module.__spec__.origin == module.__file__
。但是請注意,雖然*值*通常是等效的,但它們可能會有所不同,因為兩個物件之間沒有同步。例如,可以在執行時更新模組的__file__
,這不會自動反映在模組的__spec__.origin
中,反之亦然。在 3.4 版本中新增。
- name¶
模組的完全限定名稱(請參閱
module.__name__
)。 finder 應該始終將此屬性設定為非空字串。
- loader¶
用於載入模組的 載入器(請參閱
module.__loader__
)。 finder 應該始終設定此屬性。
- origin¶
載入器 應載入模組的位置(請參閱
module.__file__
)。例如,對於從.py
檔案載入的模組,這是檔名。 finder 應始終將此屬性設定為對 載入器 有意義的值。在不常見的情況下(例如對於名稱空間包),應將其設定為None
。
- submodule_search_locations¶
一個(可能為空的)字串 序列,列舉將找到包的子模組的位置(請參閱
module.__path__
)。大多數情況下,此列表中只有一個目錄。finder 應將此屬性設定為序列,即使是空序列,以嚮導入系統指示該模組是一個包。對於非包模組,應將其設定為
None
。稍後會自動將其設定為名稱空間包的特殊物件。
- cached¶
模組程式碼的編譯版本的檔案的檔名(請參閱
module.__cached__
)。 finder 應始終設定此屬性,但對於不需要儲存編譯程式碼的模組,該屬性可能為None
。
- parent¶
(只讀)模組所在的包的完全限定名稱(對於頂級模組,則為空字串)。請參閱
module.__package__
。如果模組是一個包,則這與name
相同。
- class importlib.machinery.AppleFrameworkLoader(name, path)¶
importlib.machinery.ExtensionFileLoader
的一個特例,它能夠載入框架格式的擴充套件模組。為了與 iOS 應用商店相容,iOS 應用中的*所有*二進位制模組都必須是動態庫,包含在具有適當元資料的框架中,並存儲在打包應用的
Frameworks
資料夾中。每個框架只能有一個二進位制檔案,並且框架資料夾之外不能有可執行二進位制檔案。為了滿足此要求,在 iOS 上執行時,擴充套件模組二進位制檔案*不*打包為
sys.path
上的.so
檔案,而是打包為獨立的框架。為了發現這些框架,此載入器將針對.fwork
副檔名進行註冊,.fwork
檔案充當sys.path
上二進位制檔案的原始位置的佔位符。.fwork
檔案包含Frameworks
資料夾中實際二進位制檔案的路徑(相對於應用包)。為了允許將框架打包的二進位制檔案解析回原始位置,框架應包含一個.origin
檔案,其中包含.fwork
檔案的位置(相對於應用包)。例如,考慮匯入
from foo.bar import _whiz
的情況,其中_whiz
是使用二進位制模組sources/foo/bar/_whiz.abi3.so
實現的,其中sources
是註冊在sys.path
上的位置(相對於應用程式包)。此模組*必須*作為Frameworks/foo.bar._whiz.framework/foo.bar._whiz
分發(從模組的完整匯入路徑建立框架名稱),在.framework
目錄中包含一個Info.plist
檔案,用於將二進位制檔案標識為框架。foo.bar._whiz
模組在原始位置用sources/foo/bar/_whiz.abi3.fwork
標記檔案表示,其中包含路徑Frameworks/foo.bar._whiz/foo.bar._whiz
。框架還將包含Frameworks/foo.bar._whiz.framework/foo.bar._whiz.origin
,其中包含.fwork
檔案的路徑。當使用此載入器載入模組時,模組的
__file__
將報告為.fwork
檔案的位置。這允許程式碼使用模組的__file__
作為檔案系統遍歷的錨點。但是,規範的來源將引用.framework
資料夾中*實際*二進位制檔案的位置。構建應用的 Xcode 專案負責將
PYTHONPATH
中存在的任何.so
檔案轉換為Frameworks
資料夾中的框架(包括從模組檔案中刪除副檔名,新增框架元資料,以及簽名生成的框架),並建立.fwork
和.origin
檔案。這通常會在 Xcode 專案中使用構建步驟來完成;有關如何構造此構建步驟的詳細資訊,請參閱 iOS 文件。在 3.13 版本中新增。
可用性:iOS。
- name¶
載入器支援的模組的名稱。
- path¶
擴充套件模組的
.fwork
檔案的路徑。
importlib.util
– 匯入器的實用程式碼¶
此模組包含有助於構建匯入器的各種物件。
- importlib.util.MAGIC_NUMBER¶
表示位元組碼版本號的位元組。如果您需要載入/寫入位元組碼方面的幫助,請考慮使用
importlib.abc.SourceLoader
。在 3.4 版本中新增。
- importlib.util.cache_from_source(path, debug_override=None, *, optimization=None)¶
返回與源 path 關聯的位元組編譯檔案的 PEP 3147/PEP 488 路徑。例如,如果 path 為
/foo/bar/baz.py
,則返回值對於 Python 3.2 將為/foo/bar/__pycache__/baz.cpython-32.pyc
。cpython-32
字串來自當前魔術標記 (請參閱get_tag()
;如果未定義sys.implementation.cache_tag
,則將引發NotImplementedError
)。optimization 引數用於指定位元組碼檔案的最佳化級別。空字串表示不進行最佳化,因此,optimization 為
''
的/foo/bar/baz.py
將導致位元組碼路徑為/foo/bar/__pycache__/baz.cpython-32.pyc
。None
會導致使用直譯器的最佳化級別。將使用任何其他值的字串表示形式,因此,optimization 為2
的/foo/bar/baz.py
將導致位元組碼路徑為/foo/bar/__pycache__/baz.cpython-32.opt-2.pyc
。optimization 的字串表示形式只能是字母數字,否則將引發ValueError
。debug_override 引數已棄用,可用於覆蓋系統的
__debug__
值。True
值等效於將 optimization 設定為空字串。False
值與將 optimization 設定為1
相同。如果 debug_override 和 optimization 都不為None
,則會引發TypeError
。在 3.4 版本中新增。
在 3.5 版本中更改: 添加了 optimization 引數,並棄用了 debug_override 引數。
在 3.6 版本中更改: 接受路徑類物件。
- importlib.util.source_from_cache(path)¶
給定 PEP 3147 檔名的 path,返回關聯的原始碼檔案路徑。例如,如果 path 為
/foo/bar/__pycache__/baz.cpython-32.pyc
,則返回的路徑將為/foo/bar/baz.py
。path 不需要存在,但是如果它不符合 PEP 3147 或 PEP 488 格式,則會引發ValueError
。如果未定義sys.implementation.cache_tag
,則會引發NotImplementedError
。在 3.4 版本中新增。
在 3.6 版本中更改: 接受路徑類物件。
- importlib.util.decode_source(source_bytes)¶
解碼錶示原始碼的給定位元組,並將其作為具有通用換行符的字串返回 (根據
importlib.abc.InspectLoader.get_source()
的要求)。在 3.4 版本中新增。
- importlib.util.resolve_name(name, package)¶
將相對模組名稱解析為絕對名稱。
如果 name 沒有前導點,則直接返回 name。這允許諸如
importlib.util.resolve_name('sys', __spec__.parent)
之類的用法,而無需檢查是否需要 package 引數。如果 name 是相對模組名稱,但是 package 為假值(例如
None
或空字串),則會引發ImportError
。如果相對名稱將逃脫其包含的包(例如,從spam
包內請求..bacon
),也會引發ImportError
。在 3.3 版本中新增。
在 3.9 版本中更改: 為了提高與 import 語句的一致性,對於無效的相對匯入嘗試,引發
ImportError
,而不是ValueError
。
- importlib.util.find_spec(name, package=None)¶
查詢模組的規範,可以選擇相對於指定的 package 名稱。如果模組在
sys.modules
中,則返回sys.modules[name].__spec__
(除非規範為None
或未設定,在這種情況下會引發ValueError
)。否則,將使用sys.meta_path
進行搜尋。如果未找到規範,則返回None
。如果 name 用於子模組(包含點),則會自動匯入父模組。
name 和 package 的工作方式與
import_module()
相同。在 3.4 版本中新增。
在 3.7 版本中更改: 如果 package 實際上不是一個包(即缺少
__path__
屬性),則引發ModuleNotFoundError
而不是AttributeError
。
- importlib.util.module_from_spec(spec)¶
基於 spec 和
spec.loader.create_module
建立一個新模組。如果
spec.loader.create_module
沒有返回None
,那麼任何預先存在的屬性都不會被重置。此外,如果在訪問 spec 或設定模組屬性時觸發AttributeError
,也不會引發該異常。與使用
types.ModuleType
建立新模組相比,此函式是首選,因為 spec 用於儘可能多地在模組上設定受匯入控制的屬性。3.5 版本新增。
- importlib.util.spec_from_loader(name, loader, *, origin=None, is_package=None)¶
一個用於基於載入器建立
ModuleSpec
例項的工廠函式。引數的含義與它們在 ModuleSpec 中的含義相同。該函式使用可用的 載入器 API,例如InspectLoader.is_package()
,來填充 spec 上任何缺失的資訊。在 3.4 版本中新增。
- importlib.util.spec_from_file_location(name, location, *, loader=None, submodule_search_locations=None)¶
一個用於基於檔案路徑建立
ModuleSpec
例項的工廠函式。缺失的資訊將透過使用載入器 API 並隱含該模組將基於檔案來填充到 spec 中。在 3.4 版本中新增。
在 3.6 版本中更改: 接受路徑類物件。
- importlib.util.source_hash(source_bytes)¶
以位元組形式返回 source_bytes 的雜湊值。基於雜湊的
.pyc
檔案在其頭部嵌入了相應原始檔內容的source_hash()
。3.7 版本新增。
- importlib.util._incompatible_extension_module_restrictions(*, disable_check)¶
一個上下文管理器,可以臨時跳過擴充套件模組的相容性檢查。預設情況下,檢查是啟用的,當在子直譯器中匯入單階段初始化模組時,檢查將失敗。當在具有自己 GIL 的直譯器中匯入不支援每個直譯器 GIL 的多階段初始化模組時,檢查也會失敗。
請注意,此函式旨在適應一種不常見的情況;這種情況很可能會最終消失。很有可能這不是您要尋找的。
您可以透過實現多階段初始化的基本介面 (PEP 489) 並謊報對多個直譯器(或每個直譯器 GIL)的支援來獲得與此函式相同的效果。
警告
使用此函式停用檢查可能會導致意外行為,甚至崩潰。它只應在擴充套件模組開發期間使用。
在 3.12 版本中新增。
- class importlib.util.LazyLoader(loader)¶
一個類,它會延遲模組載入器的執行,直到模組的屬性被訪問為止。
這個類 只 適用於定義了
exec_module()
的載入器,因為需要控制模組使用的模組型別。出於同樣的原因,載入器的create_module()
方法必須返回None
或一個型別,該型別的__class__
屬性可以被修改,同時不使用 slots。最後,替換sys.modules
中放置的物件的模組將無法工作,因為沒有辦法安全地正確替換整個直譯器中的模組引用;如果檢測到此類替換,則會引發ValueError
。注意
對於啟動時間至關重要的專案,此類允許在模組從未使用的情況下潛在地最大限度地減少載入模組的成本。對於啟動時間不重要的專案,由於載入期間建立的錯誤訊息被延遲,從而在上下文之外發生,因此 強烈 不鼓勵使用此類。
3.5 版本新增。
在 3.6 版本中更改: 開始呼叫
create_module()
,刪除importlib.machinery.BuiltinImporter
和importlib.machinery.ExtensionFileLoader
的相容性警告。- classmethod factory(loader)¶
一個返回可呼叫物件的類方法,該可呼叫物件建立一個惰性載入器。這旨在用於載入器透過類而不是透過例項傳遞的情況。
suffixes = importlib.machinery.SOURCE_SUFFIXES loader = importlib.machinery.SourceFileLoader lazy_loader = importlib.util.LazyLoader.factory(loader) finder = importlib.machinery.FileFinder(path, (lazy_loader, suffixes))
示例¶
以程式設計方式匯入¶
要以程式設計方式匯入模組,請使用 importlib.import_module()
。
import importlib
itertools = importlib.import_module('itertools')
檢查是否可以匯入模組¶
如果您需要找出是否可以匯入模組而不實際執行匯入,那麼您應該使用 importlib.util.find_spec()
。
請注意,如果 name
是一個子模組(包含點),importlib.util.find_spec()
將匯入父模組。
import importlib.util
import sys
# For illustrative purposes.
name = 'itertools'
if name in sys.modules:
print(f"{name!r} already in sys.modules")
elif (spec := importlib.util.find_spec(name)) is not None:
# If you chose to perform the actual import ...
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
print(f"{name!r} has been imported")
else:
print(f"can't find the {name!r} module")
直接匯入原始檔¶
應謹慎使用此方法:它是匯入語句的近似表示,其中直接指定檔案路徑,而不是搜尋 sys.path
。應首先考慮替代方法,例如在需要正確的模組時修改 sys.path
,或者在執行 Python 檔案產生的全域性名稱空間合適時使用 runpy.run_path()
。
要直接從路徑匯入 Python 原始檔,請使用以下方法
import importlib.util
import sys
def import_from_path(module_name, file_path):
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module
# For illustrative purposes only (use of `json` is arbitrary).
import json
file_path = json.__file__
module_name = json.__name__
# Similar outcome as `import json`.
json = import_from_path(module_name, file_path)
實現惰性匯入¶
下面的示例展示瞭如何實現惰性匯入
>>> import importlib.util
>>> import sys
>>> def lazy_import(name):
... spec = importlib.util.find_spec(name)
... loader = importlib.util.LazyLoader(spec.loader)
... spec.loader = loader
... module = importlib.util.module_from_spec(spec)
... sys.modules[name] = module
... loader.exec_module(module)
... return module
...
>>> lazy_typing = lazy_import("typing")
>>> #lazy_typing is a real module object,
>>> #but it is not loaded in memory yet.
>>> lazy_typing.TYPE_CHECKING
False
設定匯入器¶
對於匯入的深度自定義,您通常希望實現一個 匯入器。這意味著管理 查詢器 和 載入器 兩方面。對於查詢器,根據您的需要有兩種選擇:元路徑查詢器 或 路徑條目查詢器。前者是您放在 sys.meta_path
上的,而後者是您使用 路徑條目鉤子 在 sys.path_hooks
上建立的,它與 sys.path
條目一起工作,以潛在地建立查詢器。此示例將向您展示如何註冊自己的匯入器,以便匯入將使用它們(有關為您自己建立匯入器的資訊,請閱讀此包中定義的相應類的文件)
import importlib.machinery
import sys
# For illustrative purposes only.
SpamMetaPathFinder = importlib.machinery.PathFinder
SpamPathEntryFinder = importlib.machinery.FileFinder
loader_details = (importlib.machinery.SourceFileLoader,
importlib.machinery.SOURCE_SUFFIXES)
# Setting up a meta path finder.
# Make sure to put the finder in the proper location in the list in terms of
# priority.
sys.meta_path.append(SpamMetaPathFinder)
# Setting up a path entry finder.
# Make sure to put the path hook in the proper location in the list in terms
# of priority.
sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))
近似 importlib.import_module()
¶
匯入本身是用 Python 程式碼實現的,這使得可以透過 importlib 公開大部分匯入機制。以下透過提供 importlib.import_module()
的近似實現,來幫助說明 importlib 公開的各種 API。
import importlib.util
import sys
def import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
sys.modules[absolute_name] = module
spec.loader.exec_module(module)
if path is not None:
setattr(parent_module, child_name, module)
return module