<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](expressions.xhtml "6. 表達式") | - [上一頁](executionmodel.xhtml "4. 執行模型") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 語言參考](index.xhtml) ? - $('.inline-search').show(0); | # 5. 導入系統 一個 [module](../glossary.xhtml#term-module) 內的 Python 代碼通過 [importing](../glossary.xhtml#term-importing) 操作就能夠訪問另一個模塊內的代碼。 [`import`](simple_stmts.xhtml#import) 語句是發起調用導入機制的最常用方式,但不是唯一的方式。 [`importlib.import_module()`](../library/importlib.xhtml#importlib.import_module "importlib.import_module") 以及內置的 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 等函數也可以被用來發起調用導入機制。 [`import`](simple_stmts.xhtml#import) 語句結合了兩個操作;它先搜索指定名稱的模塊,然后將搜索結果綁定到當前作用域中的名稱。 `import` 語句的搜索操作定義為對 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 函數的調用并帶有適當的參數。 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 的返回值會被用于執行 `import` 語句的名稱綁定操作。 請參閱 `import` 語句了解名稱綁定操作的更多細節。 對 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 的直接調用將僅執行模塊搜索以及在找到時的模塊創建操作。 不過也可能產生某些副作用,例如導入父包和更新各種緩存 (包括 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules")),只有 [`import`](simple_stmts.xhtml#import) 語句會執行名稱綁定操作。 當 [`import`](simple_stmts.xhtml#import) 語句被執行時,標準的內置 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 函數會被調用。 其他發起調用導入系統的機制 (例如 [`importlib.import_module()`](../library/importlib.xhtml#importlib.import_module "importlib.import_module")) 可能會選擇繞過 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 并使用它們自己的解決方案來實現導入機制。 當一個模塊首次被導入時,Python 會搜索該模塊,如果找到就創建一個 module 對象 [1](#fnmo) 并初始化它。 如果指定名稱的模塊未找到,則會引發 [`ModuleNotFoundError`](../library/exceptions.xhtml#ModuleNotFoundError "ModuleNotFoundError")。 當發起調用導入機制時,Python 會實現多種策略來搜索指定名稱的模塊。 這些策略可以通過使用使用下文所描述的多種鉤子來加以修改和擴展。 在 3.3 版更改: 導入系統已被更新以完全實現 [**PEP 302**](https://www.python.org/dev/peps/pep-0302) \[https://www.python.org/dev/peps/pep-0302\] 中的第二階段要求。 不會再有任何隱式的導入機制 —— 整個導入系統都通過 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 暴露出來。 此外,對原生命名空間包的支持也已被實現 (參見 [**PEP 420**](https://www.python.org/dev/peps/pep-0420) \[https://www.python.org/dev/peps/pep-0420\])。 ## 5.1. [`importlib`](../library/importlib.xhtml#module-importlib "importlib: The implementation of the import machinery.") [`importlib`](../library/importlib.xhtml#module-importlib "importlib: The implementation of the import machinery.") 模塊提供了一個豐富的 API 用來與導入系統進行交互。 例如 [`importlib.import_module()`](../library/importlib.xhtml#importlib.import_module "importlib.import_module") 提供了相比內置的 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 更推薦、更簡單的 API 用來發起調用導入機制。 更多細節請參看 [`importlib`](../library/importlib.xhtml#module-importlib "importlib: The implementation of the import machinery.") 庫文檔。 ## 5.2. 包 Python 只有一種模塊對象類型,所有模塊都屬于該類型,無論模塊是用 Python、C 還是別的語言實現。 為了幫助組織模塊并提供名稱層次結構,Python 還引入了 [包](../glossary.xhtml#term-package) 的概念。 你可以把包看成是文件系統中的目錄,并把模塊看成是目錄中的文件,但請不要對這個類似做過于字面的理解,因為包和模塊不是必須來自于文件系統。 為了方便理解本文檔,我們將繼續使用這種目錄和文件的類比。 與文件系統一樣,包通過層次結構進行組織,在包之內除了一般的模塊,還可以有子包。 要注意的一個重點概念是所有包都是模塊,但并非所有模塊都是包。 或者換句話說,包只是一種特殊的模塊。 特別地,任何具有 `__path__` 屬性的模塊都會被當作是包。 所有模塊都有自己的名字。 子包名與其父包名以點號分隔,與 Python 的標準屬性訪問語法一致。 例如你可能看到一個名為 [`sys`](../library/sys.xhtml#module-sys "sys: Access system-specific parameters and functions.") 的模塊,以及一個名為 [`email`](../library/email.xhtml#module-email "email: Package supporting the parsing, manipulating, and generating email messages.") 的包,這個包又有一個名為 [`email.mime`](../library/email.mime.xhtml#module-email.mime "email.mime: Build MIME messages.") 的子包和該子包中的名為 `email.mime.text` 的子包。 ### 5.2.1. 正規包 Python 定義了兩種類型的包,[正規包](../glossary.xhtml#term-regular-package) 和 [命名空間包](../glossary.xhtml#term-namespace-package)。 正規包是傳統的包類型,它們在 Python 3.2 及之前就已存在。 正規包通常以一個包含 `__init__.py` 文件的目錄形式實現。 當一個正規包被導入時,這個 `__init__.py` 文件會隱式地被執行,它所定義的對象會被綁定到該包命名空間中的名稱。`__init__.py` 文件可以包含與任何其他模塊中所包含的 Python 代碼相似的代碼,Python 將在模塊被導入時為其添加額外的屬性。 例如,以下文件系統布局定義了一個最高層級的 `parent` 包和三個子包: ``` parent/ __init__.py one/ __init__.py two/ __init__.py three/ __init__.py ``` 導入 `parent.one` 將隱式地執行 `parent/__init__.py` 和 `parent/one/__init__.py`。 后續導入 `parent.two` 或 `parent.three` 則將分別執行 `parent/two/__init__.py` 和 `parent/three/__init__.py`。 ### 5.2.2. 命名空間包 命名空間包是由多個 [部分](../glossary.xhtml#term-portion) 構成的,每個部分為父包增加一個子包。 各個部分可能處于文件系統的不同位置。 部分也可能處于 zip 文件中、網絡上,或者 Python 在導入期間可以搜索的其他地方。 命名空間包并不一定會直接對應到文件系統中的對象;它們有可能是無實體表示的虛擬模塊。 命名空間包的 `__path__` 屬性不使用普通的列表。 而是使用定制的可迭代類型,如果其父包的路徑 (或者最高層級包的 [`sys.path`](../library/sys.xhtml#sys.path "sys.path")) 發生改變,這種對象會在該包內的下一次導入嘗試時自動執行新的對包部分的搜索。 命名空間包沒有 `parent/__init__.py` 文件。 實際上,在導入搜索期間可能找到多個 `parent` 目錄,每個都由不同的部分所提供。 因此 `parent/one` 的物理位置不一定與 `parent/two` 相鄰。 在這種情況下,Python 將為頂級的 `parent` 包創建一個命名空間包,無論是它本身還是它的某個子包被導入。 另請參閱 [**PEP 420**](https://www.python.org/dev/peps/pep-0420) \[https://www.python.org/dev/peps/pep-0420\] 了解對命名空間包的規格描述。 ## 5.3. 搜索 為了開始搜索,Python 需要被導入模塊(或者包,對于當前討論來說兩者沒有差別)的完整 [限定名稱](../glossary.xhtml#term-qualified-name)。 此名稱可以來自 [`import`](simple_stmts.xhtml#import) 語句所帶的各種參數,或者來自傳給 [`importlib.import_module()`](../library/importlib.xhtml#importlib.import_module "importlib.import_module") 或 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 函數的形參。 此名稱會在導入搜索的各個階段被使用,它也可以是指向一個子模塊的帶點號路徑,例如 `foo.bar.baz`。 在這種情況下,Python 會先嘗試導入 `foo`,然后是 `foo.bar`,最后是 `foo.bar.baz`。 如果這些導入中的任何一個失敗,都會引發 [`ModuleNotFoundError`](../library/exceptions.xhtml#ModuleNotFoundError "ModuleNotFoundError")。 ### 5.3.1. 模塊緩存 在導入搜索期間首先會被檢查的地方是 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules")。 這個映射起到緩存之前導入的所有模塊的作用(包括其中間路徑)。 因此如果之前導入過 `foo.bar.baz`,則 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 將包含 `foo`, `foo.bar` 和 `foo.bar.baz` 條目。 每個鍵的值就是相應的模塊對象。 在導入期間,會在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 查找模塊名稱,如存在則其關聯的值就是需要導入的模塊,導入過程完成。 然而,如果值為 `None`,則會引發 [`ModuleNotFoundError`](../library/exceptions.xhtml#ModuleNotFoundError "ModuleNotFoundError")。 如果找不到指定模塊名稱,Python 將繼續搜索該模塊。 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 是可寫的。刪除鍵可能不會破壞關聯的模塊(因為其他模塊可能會保留對它的引用),但它會使命名模塊的緩存條目無效,導致 Python 在下次導入時重新搜索命名模塊。鍵也可以賦值為 `None` ,強制下一次導入模塊導致 [`ModuleNotFoundError`](../library/exceptions.xhtml#ModuleNotFoundError "ModuleNotFoundError") 。 但是要小心,因為如果你還保有對某個模塊對象的引用,同時停用其在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中的緩存條目,然后又再次導入該名稱的模塊,則前后兩個模塊對象將 *不是* 同一個。 相反地,[`importlib.reload()`](../library/importlib.xhtml#importlib.reload "importlib.reload") 將重用 *同一個* 模塊對象,并簡單地通過重新運行模塊的代碼來重新初始化模塊內容。 ### 5.3.2. 查找器和加載器 如果指定名稱的模塊在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 找不到,則將發起調用 Python 的導入協議以查找和加載該模塊。 此協議由兩個概念性模塊構成,即 [查找器](../glossary.xhtml#term-finder) 和 [加載器](../glossary.xhtml#term-loader)。 查找器的任務是確定是否能使用其所知的策略找到該名稱的模塊。 同時實現這兩種接口的對象稱為 [導入器](../glossary.xhtml#term-importer) —— 它們在確定能加載所需的模塊時會返回其自身。 Python 包含了多個默認查找器和導入器。 第一個知道如何定位內置模塊,第二個知道如何定位凍結模塊。 第三個默認查找器會在 [import path](../glossary.xhtml#term-import-path) 中搜索模塊。 [import path](../glossary.xhtml#term-import-path) 是一個由文件系統路徑或 zip 文件組成的位置列表。 它還可以擴展為搜索任意可定位資源,例如由 URL 指定的資源。 導入機制是可擴展的,因此可以加入新的查找器以擴展模塊搜索的范圍和作用域。 查找器并不真正加載模塊。 如果它們能找到指定名稱的模塊,會返回一個 *模塊規格說明*,這是對模塊導入相關信息的封裝,供后續導入機制用于在加載模塊時使用。 以下各節描述了有關查找器和加載器協議的更多細節,包括你應該如何創建并注冊新的此類對象來擴展導入機制。 在 3.4 版更改: 在之前的 Python 版本中,查找器會直接返回 [加載器](../glossary.xhtml#term-loader),現在它們則返回模塊規格說明,其中 *包含* 加載器。 加載器仍然在導入期間被使用,但負擔的任務有所減少。 ### 5.3.3. 導入鉤子 導入機制被設計為可擴展;其中的基本機制是 *導入鉤子*。 導入鉤子有兩種類型: *元鉤子* 和 *導入路徑鉤子*。 元鉤子在導入過程開始時被調用,此時任何其他導入過程尚未發生,但 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 緩存查找除外。 這允許元鉤子重載 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 過程、凍結模塊甚至內置模塊。 元鉤子的注冊是通過向 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 添加新的查找器對象,具體如下所述。 導入路徑鉤子是作為 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") (或 `package.__path__`) 過程的一部分,在遇到它們所關聯的路徑項的時候被調用。 導入路徑鉤子的注冊是通過向 [`sys.path_hooks`](../library/sys.xhtml#sys.path_hooks "sys.path_hooks") 添加新的可調用對象,具體如下所述。 ### 5.3.4. 元路徑 當指定名稱的模塊在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中找不到時,Python 會接著搜索 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path"),其中包含元路徑查找器對象列表。 這些查找器按順序被查詢以確定它們是否知道如何處理該名稱的模塊。 元路徑查找器必須實現名為 [`find_spec()`](../library/importlib.xhtml#importlib.abc.MetaPathFinder.find_spec "importlib.abc.MetaPathFinder.find_spec") 的方法,該方法接受三個參數:名稱、導入路徑和目標模塊(可選)。 元路徑查找器可使用任何策略來確定它是否能處理指定名稱的模塊。 如果元路徑查找器知道如何處理指定名稱的模塊,它將返回一個說明對象。 如果它不能處理該名稱的模塊,則會返回 `None`。 如果 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 處理過程到達列表末尾仍未返回說明對象,則將引發 [`ModuleNotFoundError`](../library/exceptions.xhtml#ModuleNotFoundError "ModuleNotFoundError")。 任何其他被引發異常將直接向上傳播,并放棄導入過程。 元路徑查找器的 [`find_spec()`](../library/importlib.xhtml#importlib.abc.MetaPathFinder.find_spec "importlib.abc.MetaPathFinder.find_spec") 方法調用帶有兩到三個參數。 第一個是被導入模塊的完整限定名稱,例如 `foo.bar.baz`。 第二個參數是供模塊搜索使用的路徑條目。 對于最高層級模塊,第二個參數為 `None`,但對于子模塊或子包,第二個參數為父包 `__path__` 屬性的值。 如果相應的 `__path__` 屬性無法訪問,將引發 [`ModuleNotFoundError`](../library/exceptions.xhtml#ModuleNotFoundError "ModuleNotFoundError")。 第三個參數是一個將被作為稍后加載目標的現有模塊對象。 導入系統僅會在重加載期間傳入一個目標模塊。 對于單個導入請求可以多次遍歷元路徑。 例如,假設所涉及的模塊都尚未被緩存,則導入 `foo.bar.baz` 將首先執行頂級的導入,在每個元路徑查找器 (`mpf`) 上調用 `mpf.find_spec("foo", None, None)`。 在導入 `foo` 之后,`foo.bar` 將通過第二次遍歷元路徑來導入,調用 `mpf.find_spec("foo.bar", foo.__path__, None)`。 一旦 `foo.bar` 完成導入,最后一次遍歷將調用 `mpf.find_spec("foo.bar.baz", foo.bar.__path__, None)`。 有些元路徑查找器只支持頂級導入。 當把 `None` 以外的對象作為第三個參數傳入時,這些導入器將總是返回 `None`。 Python 的默認 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 具有三種元路徑查找器,一種知道如何導入內置模塊,一種知道如何導入凍結模塊,還有一種知道如何導入來自 [import path](../glossary.xhtml#term-import-path) 的模塊 (即 [path based finder](../glossary.xhtml#term-path-based-finder))。 在 3.4 版更改: 元路徑查找器的 [`find_spec()`](../library/importlib.xhtml#importlib.abc.MetaPathFinder.find_spec "importlib.abc.MetaPathFinder.find_spec") 方法替代了 [`find_module()`](../library/importlib.xhtml#importlib.abc.MetaPathFinder.find_module "importlib.abc.MetaPathFinder.find_module"),后者現已棄用,它將繼續可用但不會再做改變,導入機制僅會在查找器未實現 `find_spec()` 時嘗試使用它。 ## 5.4. 加載 當一個模塊說明被找到時,導入機制將在加載該模塊時使用它(及其所包含的加載器)。 下面是導入的加載部分所發生過程的簡要說明: ``` module = None if spec.loader is not None and hasattr(spec.loader, 'create_module'): # It is assumed 'exec_module' will also be defined on the loader. module = spec.loader.create_module(spec) if module is None: module = ModuleType(spec.name) # The import-related module attributes get set here: _init_module_attrs(spec, module) if spec.loader is None: if spec.submodule_search_locations is not None: # namespace package sys.modules[spec.name] = module else: # unsupported raise ImportError elif not hasattr(spec.loader, 'exec_module'): module = spec.loader.load_module(spec.name) # Set __loader__ and __package__ if missing. else: sys.modules[spec.name] = module try: spec.loader.exec_module(module) except BaseException: try: del sys.modules[spec.name] except KeyError: pass raise return sys.modules[spec.name] ``` 請注意以下細節: > - 如果在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中存在指定名稱的模塊對象,導入操作會已經將其返回。 > - 在加載器執行模塊代碼之前,該模塊將存在于 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中。 這一點很關鍵,因為該模塊代碼可能(直接或間接地)導入其自身;預先將其添加到 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 可防止在最壞情況下的無限遞歸和最好情況下的多次加載。 > - 如果加載失敗,則該模塊 -- 只限加載失敗的模塊 -- 將從 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中移除。 任何已存在于 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 緩存的模塊,以及任何作為附帶影響被成功加載的模塊仍會保留在緩存中。 這與重新加載不同,后者會把即使加載失敗的模塊也保留在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中。 > - 在模塊創建完成但還未執行之前,導入機制會設置導入相關模塊屬性(在上面的示例偽代碼中為 “\_init\_module\_attrs”),詳情參見 [后續部分](#import-mod-attrs)。 > - 模塊執行是加載的關鍵時刻,在此期間將填充模塊的命名空間。 執行會完全委托給加載器,由加載器決定要填充的內容和方式。 > - 在加載過程中創建并傳遞給 exec\_module() 的模塊并不一定就是在導入結束時返回的模塊 [2](#fnlo)。 在 3.4 版更改: 導入系統已經接管了加載器建立樣板的責任。 這些在以前是由 [`importlib.abc.Loader.load_module()`](../library/importlib.xhtml#importlib.abc.Loader.load_module "importlib.abc.Loader.load_module") 方法來執行的。 ### 5.4.1. 加載器 模塊加載器提供關鍵的加載功能:模塊執行。 導入機制調用 [`importlib.abc.Loader.exec_module()`](../library/importlib.xhtml#importlib.abc.Loader.exec_module "importlib.abc.Loader.exec_module") 方法并傳入一個參數來執行模塊對象。 從 [`exec_module()`](../library/importlib.xhtml#importlib.abc.Loader.exec_module "importlib.abc.Loader.exec_module") 返回的任何值都將被忽略。 加載器必須滿足下列要求: > - 如果模塊是一個 Python 模塊(而非內置模塊或動態加載的擴展),加載器應該在模塊的全局命名空間 (`module.__dict__`) 中執行模塊的代碼。 > - 如果加載器無法執行指定模塊,它應該引發 [`ImportError`](../library/exceptions.xhtml#ImportError "ImportError"),不過在 [`exec_module()`](../library/importlib.xhtml#importlib.abc.Loader.exec_module "importlib.abc.Loader.exec_module") 期間引發的任何其他異常也會被傳播。 在許多情況下,查找器和加載器可以是同一對象;在此情況下 [`find_spec()`](../library/importlib.xhtml#importlib.abc.MetaPathFinder.find_spec "importlib.abc.MetaPathFinder.find_spec") 方法將返回一個規格說明,其中加載器會被設為 `self`。 模塊加載器可以選擇通過實現 [`create_module()`](../library/importlib.xhtml#importlib.abc.Loader.create_module "importlib.abc.Loader.create_module") 方法在加載期間創建模塊對象。 它接受一個參數,即模塊規格說明,并返回新的模塊對象供加載期間使用。 `create_module()` 不需要在模塊對象上設置任何屬性。 如果模塊返回 `None`,導入機制將自行創建新模塊。 3\.4 新版功能: 加載器的 [`create_module()`](../library/importlib.xhtml#importlib.abc.Loader.create_module "importlib.abc.Loader.create_module") 方法。 在 3.4 版更改: [`load_module()`](../library/importlib.xhtml#importlib.abc.Loader.load_module "importlib.abc.Loader.load_module") 方法被 [`exec_module()`](../library/importlib.xhtml#importlib.abc.Loader.exec_module "importlib.abc.Loader.exec_module") 所替代,導入機制會對加載的所有樣板責任作出假定。 為了與現有的加載器兼容,導入機制會使用導入器的 `load_module()` 方法,如果它存在且導入器也未實現 `exec_module()`。 但是,`load_module()` 現已棄用,加載器應該轉而實現 `exec_module()`。 除了執行模塊之外,`load_module()` 方法必須實現上文描述的所有樣板加載功能。 所有相同的限制仍然適用,并帶有一些附加規定: > - 如果 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中存在指定名稱的模塊對象,加載器必須使用已存在的模塊。 (否則 [`importlib.reload()`](../library/importlib.xhtml#importlib.reload "importlib.reload") 將無法正確工作。) 如果該名稱模塊不存在于 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中,加載器必須創建一個新的模塊對象并將其加入 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules")。 > - 在加載器執行模塊代碼之前,模塊 *必須* 存在于 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 之中,以防止無限遞歸或多次加載。 > - 如果加載失敗,加載器必須移除任何它已加入到 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中的模塊,但它必須 **僅限** 移除加載失敗的模塊,且所移除的模塊應為加載器自身顯式加載的。 在 3.5 版更改: 當 `exec_module()` 已定義但 `create_module()` 未定義時將引發 [`DeprecationWarning`](../library/exceptions.xhtml#DeprecationWarning "DeprecationWarning")。 在 3.6 版更改: 當 `exec_module()` 已定義但 `create_module()` 未定義時將引發 [`ImportError`](../library/exceptions.xhtml#ImportError "ImportError")。 ### 5.4.2. 子模塊 當使用任意機制 (例如 `importlib` API, `import` 及 `import-from` 語句或者內置的 `__import__()`) 加載一個子模塊時,父模塊的命名空間中會添加一個對子模塊對象的綁定。 例如,如果包 `spam` 有一個子模塊 `foo`,則在導入 `spam.foo` 之后,`spam` 將具有一個 綁定到相應子模塊的 `foo` 屬性。 假如現在有如下的目錄結構: ``` spam/ __init__.py foo.py bar.py ``` 并且 `spam/__init__.py` 中有如下幾行內容: ``` from .foo import Foo from .bar import Bar ``` 則執行如下代碼將在 `spam` 模塊中添加對 `foo` 和 `bar` 的名稱綁定: ``` >>> import spam >>> spam.foo <module 'spam.foo' from '/tmp/imports/spam/foo.py'> >>> spam.bar <module 'spam.bar' from '/tmp/imports/spam/bar.py'> ``` 按照通常的 Python 名稱綁定規則,這看起來可能會令人驚訝,但它實際上是導入系統的一個基本特性。 保持不變的一點是如果你有 `sys.modules['spam']` 和 `sys.modules['spam.foo']` (例如在上述導入之后就是如此),則后者必須顯示為前者的 `foo` 屬性。 ### 5.4.3. 模塊規格說明 導入機制在導入期間會使用有關每個模塊的多種信息,特別是加載之前。 大多數信息都是所有模塊通用的。 模塊規格說明的目的是基于每個模塊來封裝這些導入相關信息。 在導入期間使用規格說明可允許狀態在導入系統各組件之間傳遞,例如在創建模塊規格說明的查找器和執行模塊的加載器之間。 最重要的一點是,它允許導入機制執行加載的樣板操作,在沒有模塊規格說明的情況下這是加載器的責任。 模塊的規格說明會作為模塊對象的 `__spec__` 屬性對外公開。 有關模塊規格的詳細內容請參閱 [`ModuleSpec`](../library/importlib.xhtml#importlib.machinery.ModuleSpec "importlib.machinery.ModuleSpec")。 3\.4 新版功能. ### 5.4.4. 導入相關的模塊屬性 導入機制會在加載期間會根據模塊的規格說明填充每個模塊對象的這些屬性,并在加載器執行模塊之前完成。 `__name__``__name__` 屬性必須被設為模塊的完整限定名稱。 此名稱被用來在導入系統中唯一地標識模塊。 `__loader__``__loader__` 屬性必須被設為導入系統在加載模塊時使用的加載器對象。 這主要是用于內省,但也可用于額外的加載器專用功能,例如獲取關聯到加載器的數據。 `__package__`模塊的 `__package__` 屬性必須設定。 其取值必須為一個字符串,但可以與 `__name__` 取相同的值。 當模塊是包時,其 `__package__` 值應該設為其 `__name__` 值。 當模塊不是包時,對于最高層級模塊 `__package__` 應該設為空字符串,對于子模塊則應該設為其父包名。 更多詳情可參閱 [**PEP 366**](https://www.python.org/dev/peps/pep-0366) \[https://www.python.org/dev/peps/pep-0366\]。 該屬性取代 `__name__` 被用來為主模塊計算顯式相對導入,相關定義見 [**PEP 366**](https://www.python.org/dev/peps/pep-0366) \[https://www.python.org/dev/peps/pep-0366\]。 預期它與 `__spec__.parent` 具有相同的值。 在 3.6 版更改: `__package__` 預期與 `__spec__.parent` 具有相同的值。 `__spec__``__spec__` 屬性必須設為在導入模塊時要使用的模塊規格說明。 對 `__spec__` 的正確設定將同時作用于 [解釋器啟動期間初始化的模塊](toplevel_components.xhtml#programs)。 唯一的例外是 `__main__`,其中的 `__spec__` 會 [在某些情況下設為 None](#main-spec). 當 `__package__` 未定義時, `__spec__.parent` 會被用作回退項。 3\.4 新版功能. 在 3.6 版更改: 當 `__package__` 未定義時,`__spec__.parent` 會被用作回退項。 `__path__`如果模塊為包(不論是正規包還是命名空間包),則必須設置模塊對象的 `__path__` 屬性。 屬性值必須為可迭代對象,但如果 `__path__` 沒有進一步的用處則可以為空。 如果 `__path__` 不為空,則在迭代時它應該產生字符串。 有關 `__path__` 語義的更多細節將在 [下文](#package-path-rules) 中給出。 不是包的模塊不應該具有 `__path__` 屬性。 `__file__``__cached__``__file__` 是可選項。 如果設置,此屬性的值必須為字符串。 導入系統可以選擇在其沒有語法意義時不設置 `__file__` (例如從數據庫加載的模塊)。 如果設置了 `__file__`,則也可以再設置 `__cached__` 屬性,后者取值為編譯版本代碼(例如字節碼文件)所在的路徑。 設置此屬性不要求文件已存在;該路徑可以簡單地指向應該存放編譯文件的位置 (參見 [**PEP 3147**](https://www.python.org/dev/peps/pep-3147) \[https://www.python.org/dev/peps/pep-3147\])。 當未設置 `__file__` 時也可以設置 `__cached__`。 但是,那樣的場景很不典型。 最終,加載器會使用 `__file__` 和/或 `__cached__`。 因此如果一個加載器可以從緩存加載模塊但是不能從文件加載,那種非典型場景就是適當的。 ### 5.4.5. module.\_\_path\_\_ 根據定義,如果一個模塊具有 `__path__` 屬性,它就是包。 包的 `__path__` 屬性會在導入其子包期間被使用。 在導入機制內部,它的功能與 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 基本相同,即在導入期間提供一個模塊搜索位置列表。 但是,`__path__` 通常會比 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 受到更多限制。 `__path__` 必須是由字符串組成的可迭代對象,但它也可以為空。 作用于 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 的規則同樣適用于包的 `__path__`,并且 [`sys.path_hooks`](../library/sys.xhtml#sys.path_hooks "sys.path_hooks") (見下文) 會在遍歷包的 `__path__` 時被查詢。 包的 `__init__.py` 文件可以設置或更改包的 `__path__` 屬性,而且這是在 [**PEP 420**](https://www.python.org/dev/peps/pep-0420) \[https://www.python.org/dev/peps/pep-0420\] 之前實現命名空間包的典型方式。 隨著 [**PEP 420**](https://www.python.org/dev/peps/pep-0420) \[https://www.python.org/dev/peps/pep-0420\] 的引入,命名空間包不再需要提供僅包含 `__path__` 操控代碼的 `__init__.py` 文件;導入機制會自動為命名空間包正確地設置 `__path__`。 ### 5.4.6. 模塊的 repr 默認情況下,全部模塊都具有一個可用的 repr,但是你可以依據上述的屬性設置,在模塊的規格說明中更為顯式地控制模塊對象的 repr。 如果模塊具有 spec (`__spec__`),導入機制將嘗試用它來生成一個 repr。 如果生成失敗或找不到 spec,導入系統將使用模塊中的各種可用信息來制作一個默認 repr。 它將嘗試使用 `module.__name__`, `module.__file__` 以及 `module.__loader__` 作為 repr 的輸入,并將任何丟失的信息賦為默認值。 以下是所使用的確切規則: > - 如果模塊具有 `__spec__` 屬性,其中的規格信息會被用來生成 repr。 被查詢的屬性有 "name", "loader", "origin" 和 "has\_location" 等等。 > - 如果模塊具有 `__file__` 屬性,這會被用作模塊 repr 的一部分。 > - 如果模塊沒有 `__file__` 但是有 `__loader__` 且取值不為 `None`,則加載器的 repr 會被用作模塊 repr 的一部分。 > - 對于其他情況,僅在 repr 中使用模塊的 `__name__`。 在 3.4 版更改: [`loader.module_repr()`](../library/importlib.xhtml#importlib.abc.Loader.module_repr "importlib.abc.Loader.module_repr") 已棄用,導入機制現在使用模塊規格說明來生成模塊 repr。 為了向后兼容 Python 3.3,如果加載器定義了 [`module_repr()`](../library/importlib.xhtml#importlib.abc.Loader.module_repr "importlib.abc.Loader.module_repr") 方法,則會在嘗試上述兩種方式之前先調用該方法來生成模塊 repr。 但請注意此方法已棄用。 ### 5.4.7. 已緩存字節碼的失效 在 Python 從 `.pyc` 文件加載已緩存字節碼之前,它會檢查緩存是否由最新的 `.py` 源文件生成。 默認情況下,Python 通過在所寫入緩存文件中保存源文件的最近修改時間戳和大小來實現這一點。 在運行時,導入系統會通過比對緩存文件中保存的元數據和源文件的元數據確定該緩存的有效性。 Python 也支持“基于哈希的”緩存文件,即保存源文件內容的哈希值而不是其元數據。 存在兩種基于哈希的 `.pyc` 文件:檢查型和非檢查型。 對于檢查型基于哈希的 `.pyc` 文件,Python 會通過求哈希源文件并將結果哈希值與緩存文件中的哈希值比對來確定緩存有效性。 如果檢查型基于哈希的緩存文件被確定為失效,Python 會重新生成并寫入一個新的檢查型基于哈希的緩存文件。 對于非檢查型 `.pyc` 文件,只要其存在 Python 就會直接認定緩存文件有效。 確定基于哈希的 `.pyc` 文件有效性的行為可通過 [`--check-hash-based-pycs`](../using/cmdline.xhtml#cmdoption-check-hash-based-pycs) 旗標來重載。 在 3.7 版更改: 增加了基于哈希的 `.pyc` 文件。在此之前,Python 只支持基于時間戳來確定字節碼緩存的有效性。 ## 5.5. 基于路徑的查找器 在之前已經提及,Python 帶有幾種默認的元路徑查找器。 其中之一是 [path based finder](../glossary.xhtml#term-path-based-finder) ([`PathFinder`](../library/importlib.xhtml#importlib.machinery.PathFinder "importlib.machinery.PathFinder")),它會搜索包含一個 [路徑條目](../glossary.xhtml#term-path-entry) 列表的 [import path](../glossary.xhtml#term-import-path)。 每個路徑條目指定一個用于搜索模塊的位置。 基于路徑的查找器自身并不知道如何進行導入。 它只是遍歷單獨的路徑條目,將它們各自關聯到某個知道如何處理特定類型路徑的路徑條目查找器。 默認的路徑條目查找器集合實現了在文件系統中查找模塊的所有語義,可處理多種特殊文件類型例如 Python 源碼 (`.py` 文件),Python 字節碼 (`.pyc` 文件) 以及共享庫 (例如 `.so` 文件)。 在標準庫中 [`zipimport`](../library/zipimport.xhtml#module-zipimport "zipimport: support for importing Python modules from ZIP archives.") 模塊的支持下,默認路徑條目查找器還能處理所有來自 zip 文件的上述文件類型。 路徑條目不必僅限于文件系統位置。 它們可以指向 URL、數據庫查詢或可以用字符串指定的任何其他位置。 基于路徑的查找器還提供了額外的鉤子和協議以便能擴展和定制可搜索路徑條目的類型。 例如,如果你想要支持網絡 URL 形式的路徑條目,你可以編寫一個實現 HTTP 語義在網絡上查找模塊的鉤子。 這個鉤子(可調用對象)應當返回一個支持下述協議的 [path entry finder](../glossary.xhtml#term-path-entry-finder),以被用來獲取一個專門針對來自網絡的模塊的加載器。 預先的警告:本節和上節都使用了 *查找器* 這一術語,并通過 [meta path finder](../glossary.xhtml#term-meta-path-finder) 和 [path entry finder](../glossary.xhtml#term-path-entry-finder) 兩個術語來明確區分它們。 這兩種類型的查找器非常相似,支持相似的協議,且在導入過程中以相似的方式運作,但關鍵的一點是要記住它們是有微妙差異的。 特別地,元路徑查找器作用于導入過程的開始,主要是啟動 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 遍歷。 相比之下,路徑條目查找器在某種意義上說是基于路徑的查找器的實現細節,實際上,如果需要從 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 移除基于路徑的查找器,并不會有任何路徑條目查找器被發起調用。 ### 5.5.1. 路徑條目查找器 [path based finder](../glossary.xhtml#term-path-based-finder) 會負責查找和加載通過 [path entry](../glossary.xhtml#term-path-entry) 字符串來指定位置的 Python 模塊和包。 多數路徑條目所指定的是文件系統中的位置,但它們并不必受限于此。 作為一種元路徑查找器,[path based finder](../glossary.xhtml#term-path-based-finder) 實現了上文描述的 [`find_spec()`](../library/importlib.xhtml#importlib.abc.MetaPathFinder.find_spec "importlib.abc.MetaPathFinder.find_spec") 協議,但是它還對外公開了一些附加鉤子,可被用來定制模塊如何從 [import path](../glossary.xhtml#term-import-path) 查找和加載。 有三個變量由 [path based finder](../glossary.xhtml#term-path-based-finder), [`sys.path`](../library/sys.xhtml#sys.path "sys.path"), [`sys.path_hooks`](../library/sys.xhtml#sys.path_hooks "sys.path_hooks") 和 [`sys.path_importer_cache`](../library/sys.xhtml#sys.path_importer_cache "sys.path_importer_cache") 所使用。 包對象的 `__path__` 屬性也會被使用。 它們提供了可用于定制導入機制的額外方式。 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 包含一個提供模塊和包搜索位置的字符串列表。 它初始化自 `PYTHONPATH` 環境變量以及多種其他特定安裝和實現的默認設置。 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 條目可指定的名稱有文件系統中的目錄、zip 文件和其他可用于搜索模塊的潛在“位置”(參見 [`site`](../library/site.xhtml#module-site "site: Module responsible for site-specific configuration.") 模塊),例如 URL 或數據庫查詢等。 在 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 中只能出現字符串和字節串;所有其他數據類型都會被忽略。 字節串條目使用的編碼由單獨的 [路徑條目查找器](../glossary.xhtml#term-path-entry-finder) 來確定。 [path based finder](../glossary.xhtml#term-path-based-finder) 是一種 [meta path finder](../glossary.xhtml#term-meta-path-finder),因此導入機制會通過調用上文描述的基于路徑的查找器的 [`find_spec()`](../library/importlib.xhtml#importlib.machinery.PathFinder.find_spec "importlib.machinery.PathFinder.find_spec") 方法來啟動 [import path](../glossary.xhtml#term-import-path) 搜索。 當要向 [`find_spec()`](../library/importlib.xhtml#importlib.machinery.PathFinder.find_spec "importlib.machinery.PathFinder.find_spec") 傳入 `path` 參數時,它將是一個可遍歷的字符串列表 —— 通常為用來在其內部進行導入的包的 `__path__` 屬性。 如果 `path` 參數為 `None`,這表示最高層級的導入,將會使用 [`sys.path`](../library/sys.xhtml#sys.path "sys.path")。 基于路徑的查找器會迭代搜索路徑中的每個條目,并且每次都查找與路徑條目對應的 [path entry finder](../glossary.xhtml#term-path-entry-finder) ([`PathEntryFinder`](../library/importlib.xhtml#importlib.abc.PathEntryFinder "importlib.abc.PathEntryFinder"))。 因為這種操作可能很耗費資源(例如搜索會有 stat() 調用的開銷),基于路徑的查找器會維持一個緩存來將路徑條目映射到路徑條目查找器。 這個緩存放于 [`sys.path_importer_cache`](../library/sys.xhtml#sys.path_importer_cache "sys.path_importer_cache") (盡管如此命名,但這個緩存實際存放的是查找器對象而非僅限于 [importer](../glossary.xhtml#term-importer) 對象)。 通過這種方式,對特定 [path entry](../glossary.xhtml#term-path-entry) 位置的 [path entry finder](../glossary.xhtml#term-path-entry-finder) 的高耗費搜索只需進行一次。 用戶代碼可以自由地從 [`sys.path_importer_cache`](../library/sys.xhtml#sys.path_importer_cache "sys.path_importer_cache") 移除緩存條目,以強制基于路徑的查找器再次執行路徑條目搜索 [3](#fnpic)。 如果路徑條目不存在于緩存中,基于路徑的查找器會迭代 [`sys.path_hooks`](../library/sys.xhtml#sys.path_hooks "sys.path_hooks") 中的每個可調用對象。 對此列表中的每個 [路徑條目鉤子](../glossary.xhtml#term-path-entry-hook) 的調用會帶有一個參數,即要搜索的路徑條目。 每個可調用對象或是返回可處理路徑條目的 [path entry finder](../glossary.xhtml#term-path-entry-finder),或是引發 [`ImportError`](../library/exceptions.xhtml#ImportError "ImportError")。 基于路徑的查找器使用 [`ImportError`](../library/exceptions.xhtml#ImportError "ImportError") 來表示鉤子無法找到與 [path entry](../glossary.xhtml#term-path-entry) 相對應的 [path entry finder](../glossary.xhtml#term-path-entry-finder)。 該異常會被忽略并繼續進行 [import path](../glossary.xhtml#term-import-path) 的迭代。 每個鉤子應該期待接收一個字符串或字節串對象;字節串對象的編碼由鉤子決定(例如可以是文件系統使用的編碼 UTF-8 或其它編碼),如果鉤子無法解碼參數,它應該引發 [`ImportError`](../library/exceptions.xhtml#ImportError "ImportError")。 如果 [`sys.path_hooks`](../library/sys.xhtml#sys.path_hooks "sys.path_hooks") 迭代結束時沒有返回 [path entry finder](../glossary.xhtml#term-path-entry-finder),則基于路徑的查找器 [`find_spec()`](../library/importlib.xhtml#importlib.machinery.PathFinder.find_spec "importlib.machinery.PathFinder.find_spec") 方法將在 [`sys.path_importer_cache`](../library/sys.xhtml#sys.path_importer_cache "sys.path_importer_cache") 中存入 `None` (表示此路徑條目沒有對應的查找器) 并返回 `None`,表示此 [meta path finder](../glossary.xhtml#term-meta-path-finder) 無法找到該模塊。 如果 [`sys.path_hooks`](../library/sys.xhtml#sys.path_hooks "sys.path_hooks") 中的某個 [path entry hook](../glossary.xhtml#term-path-entry-hook) 可調用對象的返回值 *是* 一個 [path entry finder](../glossary.xhtml#term-path-entry-finder),則以下協議會被用來向查找器請求一個模塊的規格說明,并在加載該模塊時被使用。 當前工作目錄 -- 由一個空字符串表示 -- 的處理方式與 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 中的其他條目略有不同。 首先,如果發現當前工作目錄不存在,則 [`sys.path_importer_cache`](../library/sys.xhtml#sys.path_importer_cache "sys.path_importer_cache") 中不會存放任何值。 其次,每個模塊查找會對當前工作目錄的值進行全新查找。 第三,由 [`sys.path_importer_cache`](../library/sys.xhtml#sys.path_importer_cache "sys.path_importer_cache") 所使用并由 [`importlib.machinery.PathFinder.find_spec()`](../library/importlib.xhtml#importlib.machinery.PathFinder.find_spec "importlib.machinery.PathFinder.find_spec") 所返回的路徑將是實際的當前工作目錄而非空字符串。 ### 5.5.2. 路徑條目查找器協議 為了支持模塊和已初始化包的導入,也為了給命名空間包提供組成部分,路徑條目查找器必須實現 [`find_spec()`](../library/importlib.xhtml#importlib.abc.PathEntryFinder.find_spec "importlib.abc.PathEntryFinder.find_spec") 方法。 [`find_spec()`](../library/importlib.xhtml#importlib.abc.PathEntryFinder.find_spec "importlib.abc.PathEntryFinder.find_spec") 接受兩個參數,即要導入模塊的完整限定名稱,以及(可選的)目標模塊。 `find_spec()` 返回模塊的完全填充好的規格說明。 這個規格說明總是包含“加載器”集合(但有一個例外)。 為了向導入機制提示該規格說明代表一個命名空間的 [portion](../glossary.xhtml#term-portion)。 路徑條目查找器會將規格說明中的 "loader" 設為 `None` 并將 "submodule\_search\_locations" 設為一個包含該部分的列表。 在 3.4 版更改: [`find_spec()`](../library/importlib.xhtml#importlib.abc.PathEntryFinder.find_spec "importlib.abc.PathEntryFinder.find_spec") 替代了 [`find_loader()`](../library/importlib.xhtml#importlib.abc.PathEntryFinder.find_loader "importlib.abc.PathEntryFinder.find_loader") 和 [`find_module()`](../library/importlib.xhtml#importlib.abc.PathEntryFinder.find_module "importlib.abc.PathEntryFinder.find_module"),后兩者現在都已棄用,但會在 `find_spec()` 未定義時被使用。 較舊的路徑條目查找器可能會實現這兩個已棄用的方法中的一個而沒有實現 `find_spec()`。 為保持向后兼容,這兩個方法仍會被接受。 但是,如果在路徑條目查找器上實現了 `find_spec()`,這兩個遺留方法就會被忽略。 [`find_loader()`](../library/importlib.xhtml#importlib.abc.PathEntryFinder.find_loader "importlib.abc.PathEntryFinder.find_loader") 接受一個參數,即被導入模塊的完整限定名稱。 `find_loader()` 會返回一個二元組,其中第一項為加載器,第二項為一個命名空間 [portion](../glossary.xhtml#term-portion)。 當第一項(即加載器)為 `None` 時,這意味著路徑條目查找器雖然沒有指定名稱模塊的加載器,但它知道該路徑條目為指定名稱模塊提供了一個命名空間部分。 這幾乎總是表明一種情況,即 Python 被要求導入一個并不以文件系統中的實體形式存在的命名空間包。 當一個路徑條目查找器返回的加載器為 `None` 時,該二元組返回值的第二項必須為一個序列,不過它也可以為空。 如果 `find_loader()` 所返回加載器的值不為 `None`,則該部分會被忽略,而該加載器會自基于路徑的查找器返回,終止對路徑條目的搜索。 為了向后兼容其他導入協議的實現,許多路徑條目查找器也同樣支持元路徑查找器所支持的傳統 `find_module()` 方法。 但是路徑條目查找器 `find_module()` 方法的調用絕不會帶有 `path` 參數(它們被期望記錄來自對路徑鉤子初始調用的恰當路徑信息)。 路徑條目查找器的 `find_module()` 方法已棄用,因為它不允許路徑條目查找器為命名空間包提供部分。 如果 `find_loader()` 和 `find_module()` 同時存在于一個路徑條目查找器中,導入系統將總是調用 `find_loader()` 而不選擇 `find_module()`。 ## 5.6. 替換標準導入系統 替換整個導入系統的最可靠機制是移除 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 的默認內容,,將其完全替換為自定義的元路徑鉤子。 一個可行的方式是僅改變導入語句的行為而不影響訪問導入系統的其他 API,那么替換內置的 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 函數可能就夠了。 這種技巧也可以在模塊層級上運用,即只在某個模塊內部改變導入語句的行為。 想要選擇性地預先防止在元路徑上從一個鉤子導入某些模塊(而不是完全禁用標準導入系統),直接從 [`find_spec()`](../library/importlib.xhtml#importlib.abc.MetaPathFinder.find_spec "importlib.abc.MetaPathFinder.find_spec") 引發 [`ModuleNotFoundError`](../library/exceptions.xhtml#ModuleNotFoundError "ModuleNotFoundError") 而非返回 `None` 就夠了。 返回后者表示元路徑搜索應當繼續,而引發異常則會立即終止搜索。 ## 5.7. Package Relative Imports Relative imports use leading dots. A single leading dot indicates a relative import, starting with the current package. Two or more leading dots indicate a relative import to the parent(s) of the current package, one level per dot after the first. For example, given the following package layout: ``` package/ __init__.py subpackage1/ __init__.py moduleX.py moduleY.py subpackage2/ __init__.py moduleZ.py moduleA.py ``` In either `subpackage1/moduleX.py` or `subpackage1/__init__.py`, the following are valid relative imports: ``` from .moduleY import spam from .moduleY import spam as ham from . import moduleY from ..subpackage1 import moduleY from ..subpackage2.moduleZ import eggs from ..moduleA import foo ``` Absolute imports may use either the `import <>` or `from <> import <>`syntax, but relative imports may only use the second form; the reason for this is that: ``` import XXX.YYY.ZZZ ``` should expose `XXX.YYY.ZZZ` as a usable expression, but .moduleY is not a valid expression. ## 5.8. 有關 \_\_main\_\_ 的特殊事項 對于 Python 的導入系統來說 [`__main__`](../library/__main__.xhtml#module-__main__ "__main__: The environment where the top-level script is run.") 模塊是一個特殊情況。 正如在 [另一節](toplevel_components.xhtml#programs) 中所述,`__main__` 模塊是在解釋器啟動時直接初始化的,與 [`sys`](../library/sys.xhtml#module-sys "sys: Access system-specific parameters and functions.") 和 [`builtins`](../library/builtins.xhtml#module-builtins "builtins: The module that provides the built-in namespace.") 很類似。 但是,與那兩者不同,它并不被嚴格歸類為內置模塊。 這是因為 `__main__` 被初始化的方式依賴于發起調用解釋器所附帶的旗標和其他選項。 ### 5.8.1. \_\_main\_\_.\_\_spec\_\_ 根據 [`__main__`](../library/__main__.xhtml#module-__main__ "__main__: The environment where the top-level script is run.") 被初始化的方式,`__main__.__spec__` 會被設置相應值或是 `None`。 當 Python 附加 [`-m`](../using/cmdline.xhtml#cmdoption-m) 選項啟動時,`__spec__` 會被設為相應模塊或包的模塊規格說明。 `__spec__` 也會在 `__main__` 模塊作為執行某個目錄,zip 文件或其它 [`sys.path`](../library/sys.xhtml#sys.path "sys.path") 條目的一部分加載時被填充。 在 [其余的情況](../using/cmdline.xhtml#using-on-interface-options) 下 `__main__.__spec__` 會被設為 `None`,因為用于填充 [`__main__`](../library/__main__.xhtml#module-__main__ "__main__: The environment where the top-level script is run.") 的代碼不直接與可導入的模塊相對應: - 交互型提示 - [`-c`](../using/cmdline.xhtml#cmdoption-c) 選項 - 從 stdin 運行 - 直接從源碼或字節碼文件運行 請注意在最后一種情況中 `__main__.__spec__` 總是為 `None`,*即使* 文件從技術上說可以作為一個模塊被導入。 如果想要讓 [`__main__`](../library/__main__.xhtml#module-__main__ "__main__: The environment where the top-level script is run.") 中的元數據生效,請使用 [`-m`](../using/cmdline.xhtml#cmdoption-m) 開關。 還要注意即使是在 `__main__` 對應于一個可導入模塊且 `__main__.__spec__` 被相應地設定時,它們仍會被視為 *不同的* 模塊。 這是由于以下事實:使用 `if __name__ == "__main__":` 檢測來保護的代碼塊僅會在模塊被用來填充 `__main__` 命名空間時而非普通的導入時被執行。 ## 5.9. 開放問題項 XXX 最好是能增加一個圖表。 XXX \* (import\_machinery.rst) 是否要專門增加一節來說明模塊和包的屬性,也許可以擴展或移植數據模型參考頁中的相關條目? XXX 庫手冊中的 runpy 和 pkgutil 等等應該都在頁面頂端增加指向新的導入系統章節的“另請參閱”鏈接。 XXX 是否要增加關于初始化 `__main__` 的不同方式的更多解釋? XXX 增加更多有關 `__main__` 怪異/坑人特性的信息 (例如直接從 [**PEP 395**](https://www.python.org/dev/peps/pep-0395) \[https://www.python.org/dev/peps/pep-0395\] 復制)。 ## 5.10. 參考文獻 導入機制自 Python 誕生之初至今已發生了很大的變化。 原始的 [包規格說明](https://www.python.org/doc/essays/packages/) \[https://www.python.org/doc/essays/packages/\] 仍然可以查閱,但在撰寫該文檔之后許多相關細節已被修改。 原始的 [`sys.meta_path`](../library/sys.xhtml#sys.meta_path "sys.meta_path") 規格說明見 [**PEP 302**](https://www.python.org/dev/peps/pep-0302) \[https://www.python.org/dev/peps/pep-0302\],后續的擴展說明見 [**PEP 420**](https://www.python.org/dev/peps/pep-0420) \[https://www.python.org/dev/peps/pep-0420\]。 [**PEP 420**](https://www.python.org/dev/peps/pep-0420) \[https://www.python.org/dev/peps/pep-0420\] 為 Python 3.3 引入了 [命名空間包](../glossary.xhtml#term-namespace-package)。 [**PEP 420**](https://www.python.org/dev/peps/pep-0420) \[https://www.python.org/dev/peps/pep-0420\] 還引入了 `find_loader()` 協議作為 `find_module()` 的替代。 [**PEP 366**](https://www.python.org/dev/peps/pep-0366) \[https://www.python.org/dev/peps/pep-0366\] 描述了新增的 `__package__` 屬性,用于在模塊中的顯式相對導入。 [**PEP 328**](https://www.python.org/dev/peps/pep-0328) \[https://www.python.org/dev/peps/pep-0328\] 引入了絕對和顯式相對導入,并初次提出了 `__name__` 語義,最終由 [**PEP 366**](https://www.python.org/dev/peps/pep-0366) \[https://www.python.org/dev/peps/pep-0366\] 為 `__package__` 加入規范描述。 [**PEP 338**](https://www.python.org/dev/peps/pep-0338) \[https://www.python.org/dev/peps/pep-0338\] 定義了將模塊作為腳本執行。 [**PEP 451**](https://www.python.org/dev/peps/pep-0451) \[https://www.python.org/dev/peps/pep-0451\] 在 spec 對象中增加了對每個模塊導入狀態的封裝。 它還將加載器的大部分樣板責任移交回導入機制中。 這些改變允許棄用導入系統中的一些 API 并為查找器和加載器增加一些新的方法。 腳注 [1](#id1)參見 [`types.ModuleType`](../library/types.xhtml#types.ModuleType "types.ModuleType")。 [2](#id2)importlib 實現避免直接使用返回值。 而是通過在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中查找模塊名稱來獲取模塊對象。 這種方式的間接影響是被導入的模塊可能在 [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules") 中替換其自身。 這屬于具體實現的特定行為,不保證能在其他 Python 實現中起作用。 [3](#id3)在遺留代碼中,有可能在 [`sys.path_importer_cache`](../library/sys.xhtml#sys.path_importer_cache "sys.path_importer_cache") 中找到 [`imp.NullImporter`](../library/imp.xhtml#imp.NullImporter "imp.NullImporter") 的實例。 建議將這些代碼修改為使用 `None` 代替。 詳情參見 [Porting Python code](../whatsnew/3.3.xhtml#portingpythoncode)。 ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](expressions.xhtml "6. 表達式") | - [上一頁](executionmodel.xhtml "4. 執行模型") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 語言參考](index.xhtml) ? - $('.inline-search').show(0); | ? [版權所有](../copyright.xhtml) 2001-2019, Python Software Foundation. Python 軟件基金會是一個非盈利組織。 [請捐助。](https://www.python.org/psf/donations/) 最后更新于 5月 21, 2019. [發現了問題](../bugs.xhtml)? 使用[Sphinx](http://sphinx.pocoo.org/)1.8.4 創建。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看