
當程式碼從幾十行增長到幾千行時,將所有邏輯塞在一個 .py 檔案中是一場災難。模組化 (Modularity) 是軟體工程的核心原則。透過將程式碼拆解成獨立的模組 (Modules) 與套件 (Packages),我們能提升程式碼的可讀性、可維護性與重用性。
本章將帶您掌握 Python 的引用機制,並探索強大的內建標準函式庫 (Standard Library)。
1. 模組 (Modules):單一檔案的封裝
在 Python 中,任何一個 .py 檔案都是一個模組。模組名稱就是檔案名稱 (不含副檔名)。
假設我們有一個檔案 math_utils.py:
# math_utils.py
PI = 3.14159
def add(a, b):
return a + b
def sub(a, b):
return a - b
1.1 導入模組的四種方式
# 1. 導入整個模組 (推薦,保留命名空間)
import math_utils
print(math_utils.add(10, 5))
# 2. 導入特定函數 (方便,但須注意命名衝突)
from math_utils import add, PI
print(add(10, 5))
# 3. 導入並取別名 (Alias) (常用於長名稱模組)
import math_utils as mu
print(mu.PI)
# 4. 導入所有內容 (不推薦!容易汙染命名空間)
from math_utils import *
1.2 模組搜尋路徑 (The Module Search Path)
當你輸入 import xxx 時,Python 會依照 sys.path 列表中的順序搜尋:
- 當前目錄。
- PYTHONPATH 環境變數目錄。
- 標準函式庫安裝目錄。
import sys
print(sys.path) # 查看搜尋路徑
2. 套件 (Packages):模組的集合
當模組數量變多時,我們需要用資料夾來組織它們。套件本質上就是一個包含 __init__.py 檔案的資料夾。
注意:自 Python 3.3 起,
__init__.py已非強制,但為了支援舊版及明確定義套件屬性,建議保留。
專案結構範例
my_project/
├── main.py
└── utils/ <-- 套件 (Package)
├── __init__.py <-- 標識這是一個套件
├── file_ops.py <-- 子模組 module
└── net_ops.py <-- 子模組 module
__init__.py 的作用
- 標識套件:告诉 Python 這個目錄可以被 import。
- 初始化程式碼:import 套件時會優先執行此檔案。
- 控制導出:可以在此定義
__all__列表,控制from package import *時導出的模組。
# utils/__init__.py
from .file_ops import read_file # 方便使用者直接从 utils 導入
在 main.py 中使用:
import utils
utils.read_file("data.txt") # 透過 __init__.py 轉發
3. Python 標準函式庫巡禮 (Battery Included)
Python 以 “Batteries Included” (電池已隨附) 著稱,內建了極其豐富的函式庫。
| 模組 | 用途 | 範例 |
|---|---|---|
| os | 作業系統介面 | os.listdir(), os.path.join() |
| sys | 系統參數與路徑 | sys.argv (命令列參數), sys.exit() |
| math | 數學運算 | math.sqrt(), math.sin() |
| datetime | 日期與時間 | datetime.now(), timedelta() |
| json | JSON 處理 | json.loads(), json.dumps() |
| random | 隨機數生成 | random.choice(), random.randint() |
實戰:使用 os 與 datetime 備份檔案
import os
import shutil
from datetime import datetime
def backup_file(filename):
if not os.path.exists(filename):
print("檔案不存在!")
return
# 產生時間戳記
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_name = f"{filename}_{timestamp}.bak"
shutil.copy(filename, backup_name)
print(f"備份成功:{backup_name}")
4. 關鍵慣用寫法:if __name__ == "__main__":
這是 Python 中最常見的樣板程式碼。它用來判斷模組是被直接執行還是被導入。
- 直接執行檔案時:
__name__的值為"__main__"。 - 被 import 時:
__name__的值為模組名稱 (如"math_utils")。
# powerful_script.py
def main():
print("正在執行主程式邏輯...")
if __name__ == "__main__":
# 只有當使用者在終端機輸入 `python powerful_script.py` 時才會執行
main()
這讓我們可以撰寫既能作為獨立腳本執行,又能作為模組被別人導入的程式碼(方便單元測試)。
5. 第三方套件與 pip
除了標準函式庫,Python 擁有全世界最大的開源生態系 (PyPI)。我們使用 pip (Python Package Installer) 來管理這些套件。
# 安裝套件 (如 requests)
pip install requests
# 升級套件
pip install --upgrade requests
# 列出已安裝套件
pip list
# 產生依賴清單 (requirements.txt)
pip freeze > requirements.txt
虛擬環境 (Virtual Environments)
為避免不同專案間的套件版本衝突,強烈建議每個專案使用獨立的虛擬環境。
# 建立虛擬環境 (一名為 venv)
python -m venv venv
# 啟用環境 (Windows)
venv\Scripts\activate
# 啟用環境 (Mac/Linux)
source venv/bin/activate
6. 常見問題 (FAQ)
Q1: import 循環引用 (Circular Import) 怎麼辦?
A: 當模組 A 引用 B,且 B 也引用 A 時發生。 解決方案:
- 重新架構程式碼,將共同依賴提取到第三個模組 C。
- 將
import語句移到函數內部(延遲導入),雖然不推薦但在緊急時有效。
Q2: 為什麼找不到我的模組?(ModuleNotFoundError)
A: 檢查 sys.path。Python 只會搜尋路徑列表中的目錄。如果你的模組在子目錄且沒被視為套件,可能需要手動將該目錄加入 sys.path,或者正確設置 PYTHONPATH。
7. 總結
模組化是從寫程式 (Scripting) 進階到軟體工程 (Engineering) 的關鍵一步。
本章重點回顧:
- Module: 單一
.py檔案。 - Package: 包含
__init__.py的資料夾。 - Import: 推薦使用
import module或from module import item,避免import *。 - Standard Library: 善用
os,sys,json等內建模組。 - Entry Point: 使用
if __name__ == "__main__":控制執行入口。
在掌握了基礎語法與結構後,下一章我們將進入實戰,探討 檔案處理與例外控制 (File Handling & Exceptions),學習如何與外部世界互動並處理錯誤!
延伸閱讀:
- Python 官方文件:Modules
- Python Module of the Week (介紹標準函式庫的絕佳資源)