在前幾天,我們已經建立了專案目錄與 pyproject.toml
,甚至用 Hatch 建立好了虛擬環境。
那麼接下來就要面對另一個老問題:套件要怎麼安裝,版本要怎麼控管?
這不是 Python 獨有的困擾,所有語言都有同樣的痛點。因為套件會不斷更新,API 可能變動,甚至可能帶來新的 bug。如果缺乏策略,今天能跑的程式,明天就可能壞掉。
最直覺的方法是直接安裝:
pip install requests
這會安裝當下最新的版本。
👉 適合個人實驗、一次性腳本,或版本要求不嚴格的小專案。
另一種方式是明確指定版本,在 pyproject.toml
中寫死:
[project]
dependencies = [
"requests==2.31.0",
"pydantic>=2.5,<2.6"
]
👉 適合團隊合作或需要長期維護的專案。
Python 的 PEP 440 提供了多種版本約束語法,Hatch 也完全支援:
[project]
name = "awesome-app"
requires-python = ">=3.11,<3.13"
dependencies = [
"requests>=2.32,<3", # 區間鎖定(常見做法)
"python-dateutil==2.8.*", # 只允許 patch 升級
"numpy~=1.26", # 相容版號,允許 minor 內更新
]
>=2.32,<3
):可控範圍內升級。==2.8.*
):僅允許 patch 變動。~=1.26
):允許小版本更新,但不跳大版本。👉 工程實務上,通常會依專案穩定性需求,混搭這些策略。
實務上,我們會把依賴分成兩類:
[project].dependencies
extra-dependencies
Hatch 允許你在環境下直接指定額外套件:
[tool.hatch.envs.dev]
extra-dependencies = [
"pytest>=8.3,<9",
"ruff==0.6.*",
"mypy~=1.11"
]
這樣當你執行:
hatch env create dev
Hatch 就會建立一個名為 dev
的環境,並安裝這些工具。
👉 適合快速建立專用環境,但這些依賴只存在於 Hatch 的設定裡,外部工具(例如 pip、Poetry)無法重用。
optional-dependencies
若你希望這些依賴能在 不同工具中共享,應該把它們放在 pyproject.toml
的 [project.optional-dependencies]
:
[project.optional-dependencies]
dev = ["pytest>=8.3,<9", "ruff==0.6.*", "mypy~=1.11"]
docs = ["mkdocs", "mkdocs-material"]
這樣除了 Hatch,其他工具也能用:
pip install '.[dev]'
pip install '.[docs]'
features
接著,你可以在 Hatch 的環境設定裡引用這些 extras:
[tool.hatch.envs.dev]
features = ["dev"]
[tool.hatch.envs.docs]
features = ["docs"]
hatch env create dev
→ 會自動安裝 pytest
、ruff
、mypy
。hatch env create docs
→ 會自動安裝 mkdocs
、mkdocs-material
。👉 差別在於重用性:
extra-dependencies
→ 只能在 Hatch 裡用。features
→ 直接連結到 extras([project.optional-dependencies]
),能跨工具重用。寫法 | 範例 | 適合情境 |
---|---|---|
extra-dependencies |
[tool.hatch.envs.dev].extra-dependencies = ["pytest"] |
只想在 Hatch 中加特定套件,不需要跨工具支援 |
optional-dependencies + features |
[project.optional-dependencies].dev = [...] [tool.hatch.envs.dev].features = ["dev"] |
希望依賴群組可被 pip/Poetry/Hatch 等工具重用,是工程化最佳實務 |
[project]
name = "awesome-app"
requires-python = ">=3.11,<3.13"
dependencies = [
"requests>=2.32,<3",
"numpy~=1.26",
]
[project.optional-dependencies]
dev = ["pytest>=8.3,<9", "ruff==0.6.*", "mypy~=1.11"]
docs = ["mkdocs", "mkdocs-material"]
[tool.hatch.envs.dev]
features = ["dev"]
[tool.hatch.envs.docs]
features = ["docs"]
[tool.hatch.envs.experiment]
extra-dependencies = ["rich", "httpx"]
dev
→ 引用 extras → 跨工具都能用docs
→ 同上experiment
→ 只在 Hatch 裡多裝 rich
和 httpx
,不對外公開在上述的設定完成後,你可以使用這個指令
hatch env show
他就可以在你的專案,顯示出相關的環境設定
身為 Java 開發者,我習慣透過切換不同的 JDK 版本來因應需求,但在 Python 世界,虛擬環境能做到更高層次的隔離與依賴管理。雖然各有優缺點,但這種便利性確實讓我對 Python 工程化有新的體驗。
而在本章的重點就是,依賴管理的本質,就是在 「快」 和 「穩」 之間取捨:
extra-dependencies
,直接在環境加需要的套件。optional-dependencies
+ features
,抽象成 extras,確保跨工具一致性。明天我們將進入 Day 7 - 可重現環境策略:constraints / lock 與快取,來進一步探討如何讓環境真正可重現。這就有點像 TypeScript/Node.js 專案中的 package-lock.json
或 yarn.lock
,究竟 Python 世界的解法是什麼呢?我們接著看下去。