Python 基礎概念:requirements.txt 與 pyproject.toml
簡介
在 Python 開發的過程中,套件管理是不可或缺的環節。無論是單純的腳本還是大型的 Web 應用,都會依賴第三方套件來加速開發、提升功能。若沒有一套規範的方式記錄與安裝這些套件,團隊協作、部署到測試或正式環境時就會出現「在我機器上可以跑」的尷尬情況。
傳統上,Python 社群使用 requirements.txt 來列出所有相依套件;而在近年來,隨著 PEP 517/518 的推廣與 PEP 621(project 表格) 的標準化,pyproject.toml 正逐漸成為 統一的建置與相依描述檔。本篇文章將從概念、實作、常見陷阱到最佳實務,完整說明這兩種檔案的使用方式,幫助初學者快速上手,也讓中級開發者在專案管理上更得心應手。
核心概念
1. requirements.txt 的定位
requirements.txt 是一個純文字檔,每一行寫入 套件名稱 + 版本規則,常見的格式如下:
requests==2.28.1
numpy>=1.23,<2.0
flask
優點
- 簡潔、易讀,幾乎所有的 Python 開發工具都支援。
- 直接與
pip install -r requirements.txt結合,快速安裝整批套件。
限制
- 只描述 執行階段相依,不包含建置工具(如
setuptools、wheel)或開發需求(如pytest)。 - 版本衝突的解決需要手動調整,缺乏結構化資訊。
- 只描述 執行階段相依,不包含建置工具(如
2. 為什麼需要 pyproject.toml
PEP 518(2016)首次引入 pyproject.toml,作為 建置系統的配置檔。PEP 621(2021)則擴充此檔案,使其能夠完整描述 專案的元資料與相依,取代 setup.py、setup.cfg、requirements.txt 的部分功能。
pyproject.toml 是 TOML(Tom's Obvious Minimal Language)格式,具備:
- 結構化的段落(tables)與子段落(sub‑tables)。
- 支援多種工具的設定(如
black、isort、mypy)。 - 可同時記錄 執行時相依、開發時相依(
[project.optional-dependencies])以及 建置後端([build-system])。
3. 基本結構比較
| 檔案 | 主要用途 | 主要語法 | 支援的相依類型 |
|---|---|---|---|
requirements.txt |
快速安裝執行時相依 | pkg==version、>=、< 等 |
執行時相依 |
pyproject.toml |
建置、執行、開發相依全掌握 | TOML 表格與鍵值 | 執行時、開發時、建置後端 |
程式碼範例
以下示範三個常見情境,讓你了解兩者如何搭配使用,並掌握實務技巧。
範例 1:最簡單的 requirements.txt
# requirements.txt
requests==2.28.1 # 固定版本,避免相容性問題
pandas>=1.5,<2.0 # 允許次要更新
flask # 未指定版本,安裝最新
安裝方式:
pip install -r requirements.txt
小技巧:在 CI/CD pipeline 中,使用
pip install --no-cache-dir -r requirements.txt可以避免快取造成的舊版套件問題。
範例 2:使用 pyproject.toml 定義執行時與開發時相依
# pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "awesome-tool"
version = "0.1.0"
description = "示範用的小工具"
authors = [{name = "Jane Doe", email = "jane@example.com"}]
requires-python = ">=3.9"
# 執行時相依
dependencies = [
"requests>=2.28,<3.0",
"pandas>=1.5,<2.0"
]
# 開發時相依(測試、格式化、靜態分析)
[project.optional-dependencies]
dev = [
"pytest>=7.0",
"black>=22.0",
"mypy>=0.950"
]
# 讓工具(如 black)可以直接讀取設定
[tool.black]
line-length = 88
target-version = ["py39"]
安裝所有相依(包含開發時套件):
# 先安裝建置後端
pip install -e .[dev] # -e 表示 editable 安裝,[dev] 會安裝 optional-dependencies
說明:
-e .[dev]會把當前目錄作為可編輯的套件安裝,同時拉出dev群組的相依。若只想安裝執行時相依,使用pip install .即可。
範例 3:在 requirements.txt 中引用 pyproject.toml 產生的凍結檔
在大型專案中,我們常會把 開發環境(dev)與 部署環境(prod)分開管理。pip-tools 提供 pip-compile,可以將 pyproject.toml 轉換為凍結版 requirements.txt。
# 安裝 pip-tools
pip install pip-tools
# 產生凍結檔(只保留執行時相依)
pip-compile pyproject.toml --output-file requirements.txt
產生的 requirements.txt 可能長這樣:
# This file is autogenerated by pip-compile
pandas==1.5.3 # via -r pyproject.toml
requests==2.28.2 # via -r pyproject.toml
之後的部署只需要:
pip install -r requirements.txt
優點:凍結檔保證每次部署使用 相同 版本,避免因套件更新而產生不可預期的錯誤。
範例 4:使用 poetry 管理 pyproject.toml
poetry 是一套 全功能的套件管理工具,它直接操作 pyproject.toml,不需要額外的 requirements.txt。
# 初始化專案
poetry init
# 加入執行時相依
poetry add requests pandas
# 加入開發時相依
poetry add --dev pytest black
poetry.lock 會自動產生,確保版本凍結。部署時:
poetry install --no-dev # 只安裝執行時相依
範例 5:在 CI 中同時使用 requirements.txt 與 pyproject.toml
# .github/workflows/python-ci.yml
name: Python CI
on:
push:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.11"
- name: Install build deps
run: pip install --upgrade pip setuptools wheel
- name: Install project (editable) + dev deps
run: pip install -e .[dev]
- name: Run tests
run: pytest
這個工作流程示範了 直接以 pyproject.toml 的 [project.optional-dependencies] 方式安裝開發相依,省去維護額外的 requirements-dev.txt。
常見陷阱與最佳實踐
| 陷阱 | 描述 | 解決方案 / 最佳實踐 |
|---|---|---|
| 版本衝突 | 多個套件要求不同的版本範圍,導致安裝失敗。 | 使用 pip-compile 或 poetry 產生凍結檔,或在 pyproject.toml 中明確指定兼容範圍。 |
| 忘記同步 | 修改 pyproject.toml 後,未更新 requirements.txt,部署仍使用舊版本。 |
在 CI/CD 前加入 pip-compile 步驟,或直接改用 pyproject.toml + poetry,省去同步工作。 |
將開發套件寫入 requirements.txt |
部署環境會安裝不必要的測試或格式化工具,增加映像檔大小。 | 把開發套件放在 [project.optional-dependencies](或 dev-dependencies),僅在本機或 CI 使用。 |
使用過於寬鬆的版本規則 (>= 無上限) |
未來某個重大更新可能破壞相容性。 | 建議使用 ~=, >= + < 或 ==,將上限明確限制在次要版本範圍內。 |
直接編輯 requirements.txt 而不檢查依賴樹 |
可能遺漏隱含依賴,導致執行時錯誤。 | 使用 pipdeptree 或 poetry show --tree 檢視完整依賴圖。 |
最佳實踐總結
- 以
pyproject.toml為主:將專案元資料、執行時相依、開發相依統一管理。 - 凍結版本:在部署前產生
requirements.txt(或使用poetry.lock)以保證環境一致性。 - 分離環境:使用虛擬環境(
venv、conda)或容器化(Docker)搭配上述檔案,避免系統套件污染。 - 自動化檢查:將相依衝突檢測、凍結檔產生寫入 CI,確保每次提交都通過驗證。
實際應用場景
| 場景 | 需求 | 推薦做法 |
|---|---|---|
| 個人小腳本 | 快速安裝少量套件 | 直接寫 requirements.txt,pip install -r requirements.txt |
| 團隊開發的 Flask API | 多人協作、需區分開發/測試/部署 | 使用 pyproject.toml + poetry,將 dev 群組列出測試、格式化套件;在 CI 中 poetry install --no-dev |
| 資料科學專案 | 大量相依、需 reproducible 環境 | pyproject.toml + pip-compile 產生凍結 requirements.txt,配合 Dockerfile 建立可重現的映像檔 |
| 第三方套件發布 | 必須提供 setup.cfg/pyproject.toml 給使用者 |
完全使用 pyproject.toml(PEP 621),避免 setup.py,同時在 README 中說明 pip install . 或 pip install package-name 即可 |
| CI/CD 自動化 | 每次 commit 必須測試相依完整性 | 在 workflow 中加入 pip install -U pip-tools && pip-compile pyproject.toml -o requirements.txt && pip install -r requirements.txt,確保相依凍結且一致 |
總結
requirements.txt是 最簡潔 的相依清單,適合快速安裝或小型專案。pyproject.toml則是 現代化、結構化 的專案描述檔,除了能管理執行時相依,還能同時記錄建置工具、開發相依與其他工具設定,讓專案更具可維護性。- 在實務上,結合兩者 的最佳方式是:以
pyproject.toml為唯一真相來源,利用pip-tools或poetry產生凍結的requirements.txt(或poetry.lock),保證部署環境的可預測性。 - 切記 明確版本限制、分離開發與執行相依,並把相依管理流程寫入 CI/CD,這樣才能避免「本機跑得好」的常見問題。
透過本文的概念與範例,你已經掌握了在 Python 專案中正確使用 requirements.txt 與 pyproject.toml 的方法。未來無論是個人腳本、資料分析工作流,或是大型 Web 服務,都能以一致、可靠的方式管理套件相依,讓開發、測試與部署變得更加順暢。祝你寫程式愉快,專案順利上線!