Python 模組的製作,釋出,安裝

build2024發表於2024-07-07

在 Python 當中,一個Python 檔案就是一個模組,模組的名字就是Python檔案的名字。例如:建立一個 test.py檔案,那麼test.py 就是一個模組

模組的作用:

  • 可以使我們有邏輯的去組織我們的 Python 程式碼,以庫的形式去封裝功能,非常方便的去讓呼叫者去使用模組中的功能

  • 可以定義函式,類,變數,也能包括可執行的程式碼

模組的分類:

  • 內建模組
  • 自定義的模組
  • 第三方模組

注意:
不同的模組之間可以定義相同的變數名,但是每個模組中的變數名作用域只是在本模組中

  1. Python 模組的製作以及呼叫

建立一個 自定義的Python模組 moduleTest.py其中包括了 add函式deff函式

def add(a, b):
    return a + b

def deff(x, y):
    return x - y

再建立一個 MainTest.py 模組,去呼叫 moduleTest.py 模組,如下所示:

import moduleTest

sum = moduleTest.add(12,34)
deff = moduleTest.deff(34,56)

print(f"兩個函式雲端計算結果分別是{sum, deff}")

呼叫效果如下:

image

以上是正常建立模組和呼叫模組的步驟,但一般情況下,模組寫完後,我們還需要對模組中的函式進行測試。例如,直接在moduleTest.py 模組中去測試建立好的函式 add

def add(a, b):
    return a + b

def deff(x, y):
    return x - y

res=add(2,4)
print(f'測試模組函式結果{res}')

然後,右鍵執行當前的 moduleTest.py 模組並看輸出結果看是否正常:

image

那麼,可以看到輸出的測試結果是正常的。並且我們不需要刪除測試程式碼的情況,直接在 MainTest.py 去呼叫moduleTest.py 模組,會發現,它把不該輸出的測試內容也給呼叫輸出了

image

這個是什麼情況呢?應該怎麼避免該情況的發生呢?

這種情況就是在載入外部模組的時候,把當前moduleTest.py 模組,所有的可執行的程式碼函式全部載入過來了
如何防止該種情況的發生?那麼就需要使用了 魔法屬性 __name__

魔法屬性 __name__ 作用

  • 如果當前 moduleTest.py 檔案直接執行的時候,魔法屬性 __name__ 輸出的值是__main__
  • 如果當前 moduleTest.py 檔案作為模組,供外部去引用訪問的時候,魔法屬性 __name__ 輸出的值是當前的檔名稱

可以進行測試驗證一下上面陳述:

  • moduleTest.py 檔案直接執行輸出結果:

image

  • moduleTest.py 檔案作為模組,供外部去引用訪問,輸出結果:

image

那麼,為了防止當前 moduleTest.py 模組做為自定義模組提供給外部使用的時候,也能訪問到測試的函式,就需要在 moduleTest.py 檔案中,加入以下判斷if __name__ == '__main__':

def add(a, b):
    return a + b


def deff(x, y):
    return x - y


if __name__ == '__main__':
    res = add(2, 4)
    print(f'測試模組函式結果{res}')
    print(f'模組的魔法屬性 __name__ 變數值: {__name__}')

這樣就實現了,只有當前 moduleTest.py 檔案作為主檔案直接執行的時候,才能呼叫到測試的函式。如果作為模組供外部訪問呼叫的時候就不會呼叫到測試的函式了。效果如下:

image


再額外介紹另外一個魔法屬性 __all__

魔法屬性 __all__ 作用,如果當前的 moduleTest.py 檔案做為模組供外部其他模組進行訪問呼叫的時候,並且使用匯入模組的方式為 from xxx import * 的格式匯入所有的函式時,魔法屬性 __all__會限制該種方式,只允許訪問陣列裡面列出的函式。但對 import xxx 的格式匯入不起作用。

例如:在 moduleTest.py 檔案中,加入魔法屬性 __all__,並且只新增了 add 函式

__all__=['add']

def add(a, b):
    return a + b

def deff(x, y):
    return x - y

if __name__ == '__main__':
    res = add(2, 4)
    print(f'測試模組函式結果{res}')
    print(f'模組的魔法屬性 __name__ 變數值: {__name__}')


然後在 MainTest.py 中,透過 from moduleTest import * 的格式匯入當前模組所有的函式

  • 測試呼叫在 moduleTest.py 檔案中的魔法屬性 __all__ 新增的函式 add
from  moduleTest import *

print(add(7,8))

測試結果正常

image

  • 接著,再測試 moduleTest.py 檔案中另外一個函式 deff,就直接就丟擲異常 NameError: name 'deff' is not defined,顯示該函式未定義。

image

所以,以上結果也就驗證了,使用匯入模組的方式為 from xxx import * 的格式匯入所有的函式時,魔法屬性__all__只允許該種方式訪問陣列裡面列出的函式。

但如果使用 import moduleTest 匯入方式,則不受影響。測試效果如下:

image


  1. 模組的釋出

例如,我們把當前寫好的moduleTest.py模組,進行釋出

  • 首先,建立一個自定義目錄(moduleTest),將寫好的包(模組)放到該目錄下

image

  • 接著,再在該目錄下面,建立一個 setup.py 檔案,並在檔案裡面寫入以下程式碼
from distutils.core import setup
# name 模組名稱
# version 版本號
# description 描述
# author 作用
# py_modules 要釋出的內容,釋出多個模組使用,逗號隔開
setup(name='my_module', version='1.0', description='數字計算模組',
      author='Me', py_modules=['moduleTest'])

如果在 setup.py 檔案中,使用 distutils 報錯。由於我使用的Python 版本比較高.然而在3.12 版本釋出後,就已經移除了該模組。以下是網上的資料

隨著3.12的釋出,distutils終於被移除。根據PEP 632,distutils在3.10中被標記為廢棄,在 3.12中將不再是標準庫的一部分。從distutils中匯入將導致一個錯誤,因為不會有向後相容的情況出現。
Distutils曾經是Python中軟體包管理的首選模組,但它的侷限性導致了setuptools的興起,根據Python打包使用者指南,它現在已經成為推薦的解決方案。Setuptools仍然使用distutils的一些功能,但它整合了後者的一個副本,不再依賴標準庫。Pip用setuptools替換distutils已經有一段時間了,所以在3.12中刪除傳統的distutils模組是合理的。

image

解決上面報錯辦法,需要安裝 pip install setuptools 步驟如下:

image

安裝成功後,把 setup.py 檔案中原來的 distutils.core 替換成 setuptools 即可。

from setuptools import setup
# name 模組名稱
# version 版本號
# description 描述
# author 作用
# py_modules 要釋出的內容,釋出多個模組使用,逗號隔開
setup(name='my_module', version='1.0', description='檔案統計模組',
      author='Me', py_modules=['moduleTest'])

  • 建立模組,進入 setup.py 檔案目錄,然後執行以下命令 python setup.py build

開啟命令終端,使用 cd 命令切換到 建立的moduleTest 目錄下面,執行上述命令

image

  • 模組釋出,需要把該模組生成壓縮包,執行命令python setup.py sdist

同樣使用 cd 命令切換到 moduleTest 目錄下面,執行上述命令

image

最後生成的壓縮包 my_module-1.0.tar.gz 就可以把它釋出出去,給別人安裝使用了。

  1. 模組安裝

將生成的壓縮包檔案 my_module-1.0.tar.gz 複製D盤的一個目錄下面

image

新建一個測試工程,進行安裝外部的 python 模組 my_module-1.0.tar.gz

模組安裝命令 pip install xxx

image

安裝完畢後,就可以直接在當前的專案工程中去使用到當前模組中的所有函式功能了。如下所示:

image

相關文章