importlib --- import 的實現

在 3.1 版本加入。

原始碼: Lib/importlib/__init__.py


引言

importlib 包有三個目的。

其一,在 Python 原始碼中提供 import 語句(並由此引申到 __import__() 函式)的實現。這提供了一個可移植到任何 Python 直譯器的 import 實現。它還提供了一個比用 Python 以外的程式語言實現的更容易理解的實現。

其二,此包中公開了實現 import 的元件,使使用者能更容易地建立他們自己的自定義物件(通常稱為 importer (匯入器))來參與匯入過程。

其三,該包包含一些模組,這些模組公開了用於管理 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

確定性的 pyc 檔案

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)。如果 name 是以相對方式指定的,那麼 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 模組的程式碼會被重新編譯,模組級的程式碼會重新執行,透過重用最初載入該模組的 loader(載入器),定義了一組新的物件並繫結到模組字典中的名稱。擴充套件模組的 init 函式不會被第二次呼叫。

  • 與 Python 中所有其他物件一樣,舊物件只有在它們的引用計數降為零後才會被回收。

  • 模組名稱空間中的名稱會更新以指向任何新的或更改的物件。

  • 對舊物件的其他引用(例如模組外部的名稱)不會被重新繫結以引用新物件,如果需要,必須在它們出現的每個名稱空間中進行更新。

還有一些其他注意事項:

當一個模組被重新載入時,它的字典(包含模組的全域性變數)會被保留。名稱的重新定義將覆蓋舊的定義,所以這通常不是問題。如果模組的新版本沒有定義舊版本中定義的名稱,那麼舊的定義仍然存在。如果模組維護一個全域性表或物件快取,這個特性可以被模組利用——透過 try 語句,它可以測試表是否存在,如果需要可以跳過其初始化。

try:
    cache
except NameError:
    cache = {}

重新載入內建或動態載入的模組通常不是很有用。不建議重新載入 sys__main__builtins 和其他關鍵模組。在許多情況下,擴充套件模組的設計不是為了被初始化多次,並且在重新載入時可能會以任意方式失敗。

如果一個模組使用 fromimport … 從另一個模組匯入物件,為另一個模組呼叫 reload() 並不會重新定義從它匯入的物件——一種解決方法是重新執行 from 語句,另一種是使用 import 和限定名稱(module.name)。

如果一個模組例項化了一個類的例項,重新載入定義該類的模組不會影響例項的方法定義——它們繼續使用舊的類定義。對於派生類也是如此。

在 3.4 版本加入。

在 3.7 版更改: 當被重新載入的模組缺少 ModuleSpec 時,會引發 ModuleNotFoundError

警告

此函式非執行緒安全。從多個執行緒呼叫它可能導致未預期的行為。建議使用 threading.Lock 或其他同步原語來實現執行緒安全的模組過載。

importlib.abc – 與 import 相關的抽象基類

原始碼: Lib/importlib/abc.py


importlib.abc 模組包含了 import 所使用的所有核心抽象基類。此外還提供了一些核心抽象基類的子類,以幫助實現核心 ABC。

ABC 繼承結構

object
 +-- MetaPathFinder
 +-- PathEntryFinder
 +-- Loader
      +-- ResourceLoader --------+
      +-- InspectLoader          |
           +-- ExecutionLoader --+
                                 +-- FileLoader
                                 +-- SourceLoader
class importlib.abc.MetaPathFinder

一個代表 meta path finder (元路徑查詢器) 的抽象基類。

在 3.3 版本加入。

在 3.10 版更改: 不再是 Finder 的子類。

find_spec(fullname, path, target=None)

用於為指定模組查詢 spec (規格) 的抽象方法。如果這是一個頂層匯入,path 將為 None。否則,這是一個對子包或模組的搜尋,path 將是父包的 __path__ 的值。如果找不到規格,則返回 None。傳入時,target 是一個模組物件,查詢器可以用它來做出更明智的關於返回哪個規格的猜測。importlib.util.spec_from_loader() 可能對實現具體的 MetaPathFinders 有用。

在 3.4 版本加入。

invalidate_caches()

一個可選方法,當被呼叫時,應使查詢器使用的任何內部快取失效。在使 sys.meta_path 上所有查詢器的快取失效時,由 importlib.invalidate_caches() 使用。

在 3.4 版更改: 被呼叫時返回 None,而不是 NotImplemented

class importlib.abc.PathEntryFinder

一個代表 path entry finder (路徑條目查詢器) 的抽象基類。雖然它與 MetaPathFinder 有些相似之處,但 PathEntryFinder 僅用於 importlib.machinery.PathFinder 提供的基於路徑的匯入子系統。

在 3.3 版本加入。

在 3.10 版更改: 不再是 Finder 的子類。

find_spec(fullname, target=None)

用於為指定模組查詢 spec (規格) 的抽象方法。查詢器將僅在分配給它的 path entry(路徑條目)內搜尋模組。如果找不到規格,則返回 None。傳入時,target 是一個模組物件,查詢器可以用它來做出更明智的關於返回哪個規格的猜測。importlib.util.spec_from_loader() 可能對實現具體的 PathEntryFinders 有用。

在 3.4 版本加入。

invalidate_caches()

一個可選方法,當被呼叫時,應使查詢器使用的任何內部快取失效。當使所有快取的查詢器的快取失效時,由 importlib.machinery.PathFinder.invalidate_caches() 使用。

class importlib.abc.Loader

一個 loader (載入器) 的抽象基類。有關載入器的確切定義,請參閱 PEP 302

希望支援資源讀取的載入器應實現一個 get_resource_reader() 方法,如 importlib.resources.abc.ResourceReader 所指定。

在 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 中的模組應保持不變。

載入器應該在模組上設定幾個屬性(注意,其中一些屬性在模組重新載入時可能會改變):

exec_module() 可用時,會提供向後相容的功能。

在 3.4 版更改: 在被呼叫時引發 ImportError 而不是 NotImplementedError。當 exec_module() 可用時提供功能。

自 3.4 版起已棄用,將在 3.15 版中移除: 推薦的模組載入 API 是 exec_module() (以及 create_module())。載入器應該實現它而不是 load_module()。當實現了 exec_module() 時,匯入機制會負責 load_module() 的所有其他職責。

class importlib.abc.ResourceLoader

由 TraversableResources 取代

一個 loader(載入器)的抽象基類,它實現了可選的 PEP 302 協議,用於從儲存後端載入任意資源。

自 3.7 版起已棄用: 這個 ABC 已被棄用,建議透過 importlib.resources.abc.TraversableResources 支援資源載入。這個類僅為了與該模組中的其他 ABC 向後相容而存在。

abstractmethod get_data(path)

一個返回位於 path 的資料的位元組串的抽象方法。具有類似檔案儲存後端並允許儲存任意資料的載入器可以實現這個抽象方法,以提供對所儲存資料的直接訪問。如果找不到 path,則應引發 OSErrorpath 應該使用模組的 __file__ 屬性或包的 __path__ 中的項來構造。

在 3.4 版更改: 現在會引發 OSError 而不是 NotImplementedError

class importlib.abc.InspectLoader

一個 loader(載入器)的抽象基類,它實現了可選的 PEP 302 協議,用於檢查模組的載入器。

get_code(fullname)

返回一個模組的程式碼物件,如果模組沒有程式碼物件(例如,對於內建模組),則返回 None。如果載入器找不到請求的模組,則引發 ImportError

備註

雖然該方法有預設實現,但建議為了效能儘可能地重寫它。

在 3.4 版更改: 不再是抽象的,並提供了具體實現。

abstractmethod get_source(fullname)

一個返回模組原始碼的抽象方法。它以使用 universal newlines(通用換行符)的文字字串形式返回,將所有識別的行分隔符轉換為 '\n' 字元。如果沒有可用的原始碼(例如內建模組),則返回 None。如果載入器找不到指定的模組,則引發 ImportError

在 3.4 版更改: 現在會引發 ImportError 而不是 NotImplementedError

is_package(fullname)

一個可選方法,如果模組是包,則返回真值,否則返回假值。如果 loader(載入器)找不到該模組,則會引發 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 版起已棄用,將在 3.15 版中移除: 請改用 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)

一個繼承自 ResourceLoaderExecutionLoader 的抽象基類,提供了 ResourceLoader.get_data()ExecutionLoader.get_filename() 的具體實現。

fullname 引數是載入器要處理的模組的完全解析名稱。path 引數是模組檔案的路徑。

在 3.3 版本加入。

name

載入器可以處理的模組的名稱。

path

模組檔案的路徑。

load_module(fullname)

呼叫父類的 load_module()

自 3.4 版起已棄用,將在 3.15 版中移除: 請改用 Loader.exec_module()

abstractmethod get_filename(fullname)

返回 path

abstractmethod get_data(path)

以二進位制檔案形式讀取 path,並返回其位元組內容。

class importlib.abc.SourceLoader

一個用於實現原始檔(以及可選的位元組碼檔案)載入的抽象基類。該類繼承自 ResourceLoaderExecutionLoader,要求實現以下方法:

此類定義的抽象方法是為了新增可選的位元組碼檔案支援。不實現這些可選方法(或讓它們引發 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 版起已棄用,將在 3.15 版中移除: 請改用 exec_module()

get_source(fullname)

InspectLoader.get_source() 的具體實現。

is_package(fullname)

InspectLoader.is_package() 的具體實現。如果一個模組的檔案路徑(由 ExecutionLoader.get_filename() 提供)在移除副檔名後是一個名為 __init__ 的檔案,並且 模組名稱本身不以 __init__ 結尾,那麼該模組被確定為一個包。

class importlib.abc.ResourceReader

由 TraversableResources 取代

一個提供讀取*資源*能力的 abstract base class (抽象基類)。

從這個 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)

返回一個已開啟的、用於對*資源*進行二進位制讀取的 file-like object(類檔案物件)。

如果找不到資源,將引發 FileNotFoundError

abstractmethod resource_path(resource)

返回到*資源*的檔案系統路徑。

如果資源在檔案系統上沒有具體存在,則引發 FileNotFoundError

abstractmethod is_resource(name)

如果名為 name 的專案被視為資源,則返回 True。如果 name 不存在,則引發 FileNotFoundError

abstractmethod contents()

返回一個包含包內容的字串的 iterable(可迭代物件)。請注意,並不要求迭代器返回的所有名稱都是實際的資源,例如,返回 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

一個用於內建模組的 importer。所有已知的內建模組都列在 sys.builtin_module_names 中。此類實現了 importlib.abc.MetaPathFinderimportlib.abc.InspectLoader 抽象基類。

此類僅定義了類方法,以減少例項化的需要。

在 3.5 版本發生變更: 作為 PEP 489 的一部分,內建匯入器現在實現了 Loader.create_module()Loader.exec_module()

class importlib.machinery.FrozenImporter

一個用於凍結模組的 importer。此類實現了 importlib.abc.MetaPathFinderimportlib.abc.InspectLoader 抽象基類。

此類僅定義了類方法,以減少例項化的需要。

在 3.4 版本發生變更: 增加了 create_module()exec_module() 方法。

class importlib.machinery.WindowsRegistryFinder

用於在 Windows 登錄檔中宣告的模組的 finder。此類實現了 importlib.abc.MetaPathFinder 抽象基類。

此類僅定義了類方法,以減少例項化的需要。

在 3.3 版本加入。

自 3.6 版本起棄用: 請改用 site 配置。未來版本的 Python 可能不會預設啟用此查詢器。

class importlib.machinery.PathFinder

一個用於 sys.path 和包的 __path__ 屬性的 Finder。此類實現了 importlib.abc.MetaPathFinder 抽象基類。

此類僅定義了類方法,以減少例項化的需要。

classmethod find_spec(fullname, path=None, target=None)

一個類方法,嘗試在 sys.path 上,或者如果定義了 path,則在 path 上查詢由 fullname 指定的模組的 spec。對於每個被搜尋的路徑條目,都會檢查 sys.path_importer_cache。如果找到了一個非假值的物件,那麼它將被用作 path entry finder 來尋找被搜尋的模組。如果在 sys.path_importer_cache 中沒有找到條目,則會在 sys.path_hooks 中搜索該路徑條目的查詢器,如果找到,則將其儲存在 sys.path_importer_cache 中,並向其查詢模組資訊。如果始終沒有找到查詢器,則會在快取中儲存 None 並返回 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 引數是可變數量的二元組,每個元組包含一個載入器和載入器識別的檔案字尾序列。載入器應為可呼叫物件,接受兩個引數:模組名和找到的檔案的路徑。

查詢器會根據需要快取目錄內容,並在每次模組搜尋時進行 stat 呼叫,以驗證快取是否過時。由於快取的過時依賴於作業系統檔案系統狀態資訊的粒度,因此存在一個潛在的競態條件:搜尋一個模組,建立一個新檔案,然後搜尋這個新檔案所代表的模組。如果這些操作發生得足夠快,在 stat 呼叫的粒度範圍內,那麼模組搜尋將會失敗。為了防止這種情況發生,當您動態建立一個模組時,請確保呼叫 importlib.invalidate_caches()

在 3.3 版本加入。

path

查詢器將要搜尋的路徑。

find_spec(fullname, target=None)

嘗試在 path 中查詢處理 fullname 的 spec。

在 3.4 版本加入。

invalidate_caches()

清除內部快取。

classmethod path_hook(*loader_details)

一個類方法,返回一個閉包,用於 sys.path_hooks。該閉包會返回一個 FileFinder 例項,直接使用傳遞給閉包的 path 引數,並間接使用 loader_details

如果傳遞給閉包的引數不是一個存在的目錄,則會引發 ImportError

class importlib.machinery.SourceFileLoader(fullname, path)

importlib.abc.SourceLoader 的一個具體實現,它透過子類化 importlib.abc.FileLoader 並提供其他方法的一些具體實現來完成。

在 3.3 版本加入。

name

此載入器將處理的模組的名稱。

path

原始檔的路徑。

is_package(fullname)

如果 path 似乎是一個包的路徑,則返回 True

path_stats(path)

importlib.abc.SourceLoader.path_stats() 的具體實現。

set_data(path, data)

importlib.abc.SourceLoader.set_data() 的具體實現。

load_module(name=None)

importlib.abc.Loader.load_module() 的具體實現,其中指定要載入的模組名稱是可選的。

自 3.6 版本起棄用,將在 3.15 版本中移除: 請改用 importlib.abc.Loader.exec_module()

class importlib.machinery.SourcelessFileLoader(fullname, path)

importlib.abc.FileLoader 的一個具體實現,可以匯入位元組碼檔案(即不存在原始碼檔案)。

請注意,直接使用位元組碼檔案(因此沒有原始碼檔案)會使您的模組無法在所有 Python 實現或改變了位元組碼格式的新版 Python 中使用。

在 3.3 版本加入。

name

載入器將處理的模組的名稱。

path

位元組碼檔案的路徑。

is_package(fullname)

根據 path 判斷模組是否為包。

get_code(fullname)

返回從 pathname 建立的程式碼物件。

get_source(fullname)

返回 None,因為在使用此載入器時,位元組碼檔案沒有原始碼。

load_module(name=None)

importlib.abc.Loader.load_module() 的具體實現,其中指定要載入的模組名稱是可選的。

自 3.6 版本起棄用,將在 3.15 版本中移除: 請改用 importlib.abc.Loader.exec_module()

class importlib.machinery.ExtensionFileLoader(fullname, path)

用於擴充套件模組的 importlib.abc.ExecutionLoader 的具體實現。

fullname 引數指定載入器要支援的模組名稱。path 引數是擴充套件模組檔案的路徑。

請注意,預設情況下,如果擴充套件模組未實現多階段初始化(見 PEP 489),則在子直譯器中匯入該模組將會失敗,即使在其他情況下可以成功匯入。

在 3.3 版本加入。

在 3.12 版本發生變更: 現在需要在子直譯器中使用多階段初始化。

name

載入器支援的模組名稱。

path

擴充套件模組的路徑。

create_module(spec)

根據 PEP 489,從給定的規範建立模組物件。

在 3.5 版本加入。

exec_module(module)

根據 PEP 489,初始化給定的模組物件。

在 3.5 版本加入。

is_package(fullname)

如果檔案路徑指向一個包的 __init__ 模組,則根據 EXTENSION_SUFFIXES 返回 True

get_code(fullname)

返回 None,因為擴充套件模組沒有程式碼物件。

get_source(fullname)

返回 None,因為擴充套件模組沒有原始碼。

get_filename(fullname)

返回 path

在 3.4 版本加入。

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

用於載入模組的 loader(見 module.__loader__)。finder 應該總是設定此屬性。

origin

loader 應用於載入模組的位置(見 module.__file__)。例如,對於從 .py 檔案載入的模組,這就是檔名。finder 應該總是將此屬性設定為對 loader 有意義的值。在沒有此值的罕見情況下(如名稱空間包),應將其設定為 None

submodule_search_locations

一個(可能為空的)字串 sequence,枚舉了包的子模組將被找到的位置(見 module.__path__)。大多數情況下,此列表中只有一個目錄。

finder 應該將此屬性設定為一個序列,即使是空序列,以嚮導入系統指示該模組是一個包。對於非包模組,應將其設定為 None。對於名稱空間包,它稍後會自動設定為一個特殊物件。

loader_state

finder 可以將此屬性設定為一個包含在載入模組時使用的額外的、特定於模組的資料的物件。否則,應將其設定為 None

cached

模組程式碼的編譯版本的檔名(見 module.__cached__)。finder 應該總是設定此屬性,但對於不需要儲存編譯程式碼的模組,它可能為 None

parent

(只讀)模組所在包的完全限定名稱(對於頂層模組則為空字串)。見 module.__package__。如果模組是一個包,則此值與 name 相同。

has_location

如果 spec 的 origin 指向一個可載入的位置,則為 True,否則為 False。此值影響 origin 的解釋方式以及模組的 __file__ 的填充方式。

class importlib.machinery.AppleFrameworkLoader(name, path)

importlib.machinery.ExtensionFileLoader 的一個特化版本,能夠載入框架(Framework)格式的擴充套件模組。

為了與 iOS App Store 相容,iOS 應用中的所有二進位制模組必須是動態庫,包含在帶有適當元資料的框架中,並存儲在打包應用的 Frameworks 資料夾中。每個框架只能有一個二進位制檔案,並且在 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__ 作為檔案系統遍歷的錨點。但是,spec origin 將引用實際二進位制檔案在 .framework 資料夾中的位置。

構建應用的 Xcode 專案負責將 PYTHONPATH 中任何地方的 .so 檔案轉換為 Frameworks 資料夾中的框架(包括從模組檔案中剝離副檔名、新增框架元資料和對生成的框架進行簽名),並建立 .fwork.origin 檔案。這通常透過 Xcode 專案中的構建步驟完成;有關如何構建此步驟的詳細資訊,請參閱 iOS 文件。

在 3.13 版本加入。

可用性:iOS。

name

載入器支援的模組名稱。

path

擴充套件模組的 .fwork 檔案的路徑。

importlib.util -- 匯入器的工具程式碼

原始碼: Lib/importlib/util.py


此模組包含有助於構建 importer 的各種物件。

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 引數用於指定位元組碼檔案的最佳化級別。空字串表示無最佳化,因此對於 /foo/bar/baz.py,若 optimization'',將產生位元組碼路徑 /foo/bar/__pycache__/baz.cpython-32.pycNone 會導致使用直譯器的最佳化級別。任何其他值的字串表示形式都將被使用,因此對於 /foo/bar/baz.py,若 optimization2,將導致位元組碼路徑為 /foo/bar/__pycache__/baz.cpython-32.opt-2.pycoptimization 的字串表示形式只能是字母數字,否則會引發 ValueError

debug_override 引數已棄用,可用於覆蓋系統的 __debug__ 值。一個 True 值等同於將 optimization 設定為空字串。一個 False 值等同於將 optimization 設定為 1。如果 debug_overrideoptimization 都不是 None,則會引發 TypeError

在 3.4 版本加入。

在 3.5 版本發生變更: 增加了 optimization 引數,並棄用了 debug_override 引數。

在 3.6 版本發生變更: 接受 path-like object

importlib.util.source_from_cache(path)

給定一個 PEP 3147 檔名的 path,返回相關的原始碼檔案路徑。例如,如果 path/foo/bar/__pycache__/baz.cpython-32.pyc,返回的路徑將是 /foo/bar/baz.pypath 無需存在,但如果它不符合 PEP 3147PEP 488 格式,則會引發 ValueError。如果 sys.implementation.cache_tag 未定義,則會引發 NotImplementedError

在 3.4 版本加入。

在 3.6 版本發生變更: 接受 path-like object

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)

查詢模組的 spec,可選地相對於指定的 package 名稱。如果模組在 sys.modules 中,則返回 sys.modules[name].__spec__(除非 spec 為 None 或未設定,在這種情況下會引發 ValueError)。否則,將使用 sys.meta_path 進行搜尋。如果未找到 spec,則返回 None

如果 name 是一個子模組(包含一個點),父模組將被自動匯入。

namepackage 的工作方式與 import_module() 相同。

在 3.4 版本加入。

在 3.7 版本發生變更: 如果 package 實際上不是一個包(即缺少 __path__ 屬性),則引發 ModuleNotFoundError 而不是 AttributeError

importlib.util.module_from_spec(spec)

基於 specspec.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 相同。該函式使用可用的 loader 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 版本發生變更: 接受 path-like object

importlib.util.source_hash(source_bytes)

返回 source_bytes 的雜湊值(以位元組串形式)。基於雜湊的 .pyc 檔案在其頭部嵌入了相應原始檔內容的 source_hash()

在 3.7 版本加入。

importlib.util._incompatible_extension_module_restrictions(*, disable_check)

一個可以臨時跳過擴充套件模組相容性檢查的上下文管理器。預設情況下,該檢查是啟用的,當在子直譯器中匯入單階段初始化模組時會失敗。當在擁有自己的 GIL 的直譯器中匯入一個不支援 per-interpreter GIL 的多階段初始化模組時,它也會失敗。

請注意,此函式旨在應對一種不常見的情況;這種情況很可能最終會消失。這很可能不是您要找的東西。

您可以透過實現多階段初始化的基本介面(PEP 489)並謊報對多直譯器(或 per-interpreter 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.BuiltinImporterimportlib.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")

直接匯入原始檔

此方法應謹慎使用:它是對直接指定檔案路徑的 import 語句的近似模擬,而不是搜尋 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 將使用它們(關於為你自己建立匯入器,請閱讀本包中定義的相應類的文件)。

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()

import 本身是用 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