URLhttps://learnscript.net/zh-hant/python-reference/packages/
    複製連結移至說明  範例

    Python 套件,常規套件,命名空間套件介紹

    閱讀 8:22·字數 2511·發佈 
    Youtube 頻道
    訂閱 375

    本節所講述的內容,並不完全適用於通過類別ModuleType動態建立的表示套件的模組型別物件。

    Python 套件

    Python 套件是一類特殊的模組,他並不對應同名的py腳本檔案,而是對應同名的資料夾。

    如何判斷模組是否為套件?

    在程式碼層面,如果一個模組具有__path__特性,則該模組為套件。__path__特性可用於指示套件對應的資料夾路徑。

    在互動模式中,我們嘗試檢視模組reos__path__特性。從輸出結果可以看出,模組re是套件,模組os不是套件。

    Windows
    import re
    re.__path__
    ['\\python312.zip\\re']
    import os
    os.__path__

    AttributeError: module 'os' has no attribute '__path__'. Did you mean: '__all__'?
    UNIX/Linux/macOS
    import re
    re.__path__
    ['/usr/lib/python3.11/re']
    import os
    os.__path__

    AttributeError: module 'os' has no attribute '__path__'. Did you mean: '__all__'?

    如何命名套件?

    套件的名稱預設與其對應的資料夾名稱相同,並不需要特意的命名。比如,一個名稱為workers的資料夾,其對應的套件名稱為workers

    應該稱呼模組還是套件?

    由於套件是一種特殊的模組,因此,稱呼某個套件為模組並不算錯誤,比如,re模組。

    模組

    如果你需要了解 Python 模組,可以檢視Python 模組完整名稱,模組快取介紹一節。

    Python 常規套件

    Python 常規套件對應的資料夾,擁有一個名為__init__.py的檔案,他相當於模組對應的同名py檔案,包含套件的相關程式碼。

    常規套件的儲存形式

    在編寫程式碼期間,常規套件儲存為資料夾和資料夾中__init__.py檔案。但編譯後,常規套件的相關程式碼會轉變為位元組碼並儲存在pyc檔案中。

    這裏,套件hero對應的資料夾包含__init__.py,因此hero是一個常規套件。

    hero/__init__.py
    # hero 是一個常規套件
    print('我是常規套件 hero!')

    Python 命名空間套件

    如果套件對應的資料夾未包含名為__init__.py的檔案,則該套件被稱為命名空間套件。

    命名空間套件和常規套件之間的區別

    事實上,常規套件和命名空間套件都具有命名空間的效果,在不同的常規套件或命名空間套件中,你可以定義名稱相同的內容。至於區別,除了是否包含檔案__init__.py,還有以下幾點。

    命名空間套件的__file__特性為None,而常規套件為__init__.py檔案的路徑。命名空間套件的__path__特性為_NamespacePath型別,而常規套件為串列。命名空間套件的__loader__特性為NamespaceLoader型別,而常規套件為SourceFileLoader型別。

    模組的 __loader__ 特性

    模組的__loader__特性表示用於載入該模組的載入器。

    這裏,我們新增一個空的資料夾enemies,他將對應命名空間套件。切換命令列至enemies的上級資料夾,啟動 Python 互動模式並使用import進行匯入操作,然後檢視enemies套件的相關資訊。

    Windows
    import enemies
    enemies.__file__ == None
    True
    enemies.__path__
    _NamespacePath(['\\packages\\enemies'])
    enemies.__loader__
    <_frozen_importlib_external.NamespaceLoader object at >
    UNIX/Linux/macOS
    import enemies
    enemies.__file__ == None
    True
    enemies.__path__
    _NamespacePath(['/packages/enemies'])
    enemies.__loader__
    <_frozen_importlib_external.NamespaceLoader object at >

    命名空間,有效範圍

    要了解什麽是命名空間,可以檢視程式設計教學命名空間,有效範圍介紹一節。

    zip 檔案中的 Python 套件

    zip檔案中,套件只能以常規套件的形式存在,他們應該具有腳本檔案__init__.py,否則將無法被匯入。

    在下面的範例中,壓縮檔案plants.zip含有常規套件flowers,與plants.zip處於同一目錄的腳本檔案my_plants.py,會嘗試匯入zip中的flowers套件。啟動命令列並切換至檔案my_plants.py所在的目錄,執行後可以看到相關的輸出結果。

    plants/flowers/__init__.py
    # flowers 是一個常規套件
    print('我是套件 flowers!')
    my_plants.py
    # 取得壓縮檔案 plants.zip 的絕對路徑,並新增至模組搜尋路徑
    import os
    import sys
    zip_path = os.path.abspath('plants.zip')
    sys.path.append(zip_path)
    
    # 匯入 plants.zip 中的 flowers 套件 import flowers
    我是套件 flowers!

    如果將plants.zip中的腳本檔案__init__.py刪除,那麽重複上述執行步驟會引發例外狀況ModuleNotFoundError

    Python 子模組和子套件

    套件對應的資料夾中的py檔案或子資料夾,即為該套件的子模組和子套件,子套件可以是常規套件,也可以是命名空間套件。

    Python 模組和套件的執行優先順序

    雖然這並不符合規格,但處於同一位置的模組和套件可以具有相同的名稱。在這種情況下,匯入操作將按照如下優先順序進行,常規套件的優先順序最高,模組次之,命名空間套件的優先順序最低。當同名模組或套件中的一個被匯入後,另一個將被忽略。

    在套件school中,存在子套件homework和子模組homework,其中子套件homework是一個常規套件。在腳本檔案my_school.py(與school套件對應的資料夾處於同一目錄)中,運算式import school.homework匯入的是常規套件homework,而不是模組homework

    school/homework/__init__.py
    print('功課太多了!')
    school/homework.py
    print('這裏是模組 homework!')
    my_school.py
    # 匯入套件 school 的子套件 homework,他是一個常規套件
    import school.homework
    功課太多了!

    如果把資料夾homework中的腳本檔案__init__.py刪除,那麽常規套件homework會變為命名空間套件,再次執行my_school.py將匯入模組homework

    這裏是模組 homework!

    內容分類

    原始碼

    hero/__init__.py·codebeatme/python-reference·GitHub
    plants/flowers/__init__.py·codebeatme/python-reference·GitHub
    my_plants.py·codebeatme/python-reference·GitHub
    school/homework/__init__.py·codebeatme/python-reference·GitHub
    school/homework.py·codebeatme/python-reference·GitHub
    my_school.py·codebeatme/python-reference·GitHub