
Python 入門指南 5.0
單元 18 - 模組與套件

一個 Python 檔案就是一個模組 (module) ,模組內可以定義變數 (variable) 、函數 (function) 、類別 (class) 或是任何需要的程式內容
variable
function
class
例如我們有一個程式 module_demo01.py ,裡頭簡單定義類別 ClassDemo18
1 2 3 4 5 6 7 8 9  | # 定義類別
class ClassDemo18:
    pass
# 檔名: module_demo01.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
 | 
利用關鍵字 (keyword) import ,我們可以在模組裡用其他定義好的模組內容,下例示範引入上面的 module_demo01.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18  | # 引入 module_demo01
import module_demo01
# 印出 module_demo01.ClassDemo18
print(module_demo01.ClassDemo18)
# 引入 module_demo01 中的 ClassDemo18
from module_demo01 import ClassDemo18
# 印出 ClassDemo18
print(ClassDemo18)
# 引入 module_demo01 中的 ClassDemo18 並改名為 Demo
from module_demo01 import ClassDemo18 as Demo
# 印出 Demo
print(Demo)
# 檔名: module_demo02.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
 | 
這裡示範三種引入並使用 ClassDemo18 ,首先是單純使用關鍵字 import
2 4  | import module_demo01
print(module_demo01.ClassDemo18)
 | 
import 之後空一格,接上同目錄下的 Python 程式檔案名稱,也就是模組名稱,然後使用模組中的定義就是要以模組名稱加上小數點,繼續接上 ClassDemo18 。
第二種是能夠讓 ClassDemo18 的類別名稱在程式中直接使用,這除了用到關鍵字 import 還需要關鍵字 from
6 8  | from module_demo01 import ClassDemo18
print(ClassDemo18)
 | 
簡單說,就是 from 模組名稱 import 指定識別字 (identifier) ,所以下一行就能直接使用 ClassDemo18 的名稱。
第三種是加入關鍵字 as ,將引入的識別字改名,這是因為如果我們程式中已經定義了相同名稱的識別字就會造成名稱衝突
8 10  | from module_demo01 import ClassDemo18 as Demo
print(Demo)
 | 
這樣一來, Demo 就是 ClassDemo18 ,我們可以直接使用 Demo 替代 ClassDemo18 。
執行結果如下
| $ python module_demo02.py | 
| <class 'module_demo01.ClassDemo18'> | 
| <class 'module_demo01.ClassDemo18'> | 
| <class 'module_demo01.ClassDemo18'> | 
| $ | 
如果要引入標準程式庫 (standard library) 中的模組,可以利用以上三種方式的任一種,以下簡單示範引入 random 模組
1 2 3 4 5 6 7 8 9 10 11 12 13  | # 從標準程式庫引入 random
import random
# 重複十次
for i in range(10):
    # 印出 1 到 10 之間的任意整數
    print(random.randint(1, 10))
# 檔名: module_demo03.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
 | 
第 2 行直接 import random
 2 | import random
 | 
random 是標準程式庫中處理擬隨機數的模組。
然後利用 random 中的 randint() 取得 1 到 10 之間的整數,用 for 迴圈 (loop) 印出來。
執行結果如下
| $ python module_demo03.py | 
| 8 | 
| 3 | 
| 6 | 
| 6 | 
| 8 | 
| 10 | 
| 4 | 
| 9 | 
| 8 | 
| 1 | 
| $ | 
接下來我們示範在 Python 中設定套件 (package) ,首先在 module_demo04 資料夾中新增 __init__.py 及 module_demo05.py 兩個 Python 檔案

我們先看到 module_demo05.py 的定義
1 2 3 4 5 6 7 8 9  | # 定義類別
class ClassDemo19:
    pass
# 檔名: module_demo05.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
 | 
這裡在 module_demo05.py 只有簡單定義 ClassDemo19 類別。
至於 __init__.py 在套件中一定要有,內容可以留空,不過通常是利用 __all__ 串列 (list) 設定所有可以引入的識別字字串 (string)
1 2 3 4 5 6 7  | __all__ = ["ClassDemo19"]
# 檔名: __init__.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
 | 
這樣 module_demo04 就會是套件,我們繼續在 module_demo04 資料夾外新增一個 module_demo06.py ,定義用做引入 ClassDemo19 類別

module_demo06.py 的內容如下
1 2 3 4 5 6 7 8 9 10  | # 從套件引入模組
from module_demo04 import module_demo05
# 印出模組中的類別
print(module_demo05.ClassDemo19)
# 檔名: module_demo06.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
 | 
注意關鍵字 from 之後套件加小數點,然後是模組名稱, Python 不支援 import 之後加小數點的寫法
 2 | from module_demo04 import module_demo05
 | 
然後一樣是印出類別,執行結果如下
| $ python module_demo06.py | 
| <class 'module_demo04.module_demo05.ClassDemo19'> | 
| $ | 
模組的主要用途是放定義,但是執行程式檔案也算是模組,模組中可能也希望有測試的程式碼,那模組跟執行程式檔案要怎麼區分呢?我們可以在模組中加入判斷 __name__ 是否等於 "__main__" 的陳述 (statement) ,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14  | # 定義類別
class ClassDemo20:
    pass
# 以下為執行部分
if __name__ == "__main__":
    # 印出類別
    print(ClassDemo20)
# 檔名: module_demo07.py
# 說明:《Python入門指南》的範例程式
# 網站: http://kaiching.org
# 作者: 張凱慶
# 時間: 2023 年 5 月
 | 
這是因為模組的 __name__ 是 __main__ 的話,表示這個模組現在被執行,是主要的作用域 (scope) ,此例執行結果如下
| $ python module_demo07.py | 
| <class '__main__.ClassDemo20'> | 
| $ | 
以上我們討論的是不同 Python 程式檔案的作用域,接下來我們縮小討論範圍,討論同一 Python 程式檔案中的全域變數 (global variable) 與區域變數 (local variable) 。
| 中英文術語對照 | |
|---|---|
| 類別 | class | 
| 函數 | function | 
| 全域變數 | global variable | 
| 識別字 | identifier | 
| 關鍵字 | keyword | 
| 串列 | list | 
| 區域變數 | local variable | 
| 迴圈 | loop | 
| 模組 | module | 
| 套件 | package | 
| 作用域 | scope | 
| 標準程式庫 | standard library | 
| 陳述 | statement | 
| 字串 | string | 
| 變數 | variable | 
| 重點整理 | 
|---|
| 1. 一個 Python 檔案就是一個模組,模組中可以使用其他模組定義的內容,多個模組可用套件組織管理。 | 
| 2. 若預設變數 __name__ 等於 "__main__" 的時候,表示此時這個模組為執行程式。 | 
| 3. 關鍵字 import 用來引進模組,與 from 合用則引進模組中定義的名稱,另可用星號表示引入所有名稱。 | 
| 4. 關鍵字 as 可以替引入的識別字取別稱。 | 
| 5. 套件是 Python 組織程式庫的方式,凡是套件中的資料夾需要有 __init__.py 。 | 
| 問題與討論 | 
|---|
| 1. 若甲模組中先 import 乙模組,若在程式檔案中先 import 甲模組,又 import 乙模組,這樣會發生問題嗎? | 
| 2. 為什麼模組要設計成沒有縮排的程式碼會先被執行? | 
| 3. 為什麼要替引入的識別字取別稱? | 
| 4. 什麼情況下需要組織程式庫? | 
| 練習 | 
|---|
| 1. 承接上一個單元的練習 1 ,將新程式寫在 exercise1801.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 2. 承接上一個單元的練習 2 ,將新程式寫在 exercise1802.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 3. 承接上一個單元的練習 3 ,將新程式寫在 exercise1803.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 4. 承接上一個單元的練習 4 ,將新程式寫在 exercise1804.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 5. 承接上一個單元的練習 5 ,將新程式寫在 exercise1805.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 6. 承接上一個單元的練習 6 ,將新程式寫在 exercise1806.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 7. 承接上一個單元的練習 7 ,將新程式寫在 exercise1807.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 8. 承接上一個單元的練習 8 ,將新程式寫在 exercise1808.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 9. 承接上一個單元的練習 9 ,將新程式寫在 exercise1809.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 10. 承接上一個單元的練習 10 ,將新程式寫在 exercise1810.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 11. 承接上一個單元的練習 11 ,將新程式寫在 exercise1811.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
| 12. 承接上一個單元的練習 12 ,將新程式寫在 exercise1812.py 中,加入 if __name__ == "__main__": 陳述,將測試與定義分開。 參考程式碼 | 
