本文 AI 產出,尚未審核

Python 封裝與發佈:pip install -e(可編輯安裝)


簡介

在 Python 專案的開發與測試過程中,我們常常需要在本機環境裡安裝自己的套件。若每次修改程式碼都必須重新執行 pip install .,不僅耗時,也容易忘記重新安裝,導致測試時跑到舊的版本。

pip install -e(或稱 editable install)正是為了解決這個痛點而設計的。它會在 site‑packages 中放入一個指向專案目錄的 .pth 檔,使得 Python 直接讀取原始碼,而不需要每次重新打包安裝。開發者可以即時看到程式碼變動的效果,大幅提升開發效率。

本篇文章將從概念說明、實作範例、常見陷阱與最佳實踐,以及實務應用場景,完整介紹 pip install -e 的使用方式,讓你在日常開發中玩得更順手。


核心概念

1. Editable 安裝的原理

  • 普通安裝pip install . 會先執行 setup.py sdistbdist_wheel,產生發佈檔(.tar.gz、.whl),再把檔案解壓至 site-packages。安裝完成後,Python 執行的都是 已編譯好的檔案,原始碼的任何變動都不會自動反映。
  • Editable 安裝pip install -e . 會在 site-packages 內建立一個指向專案根目錄的 .pth 檔(例如 myproj.pth),並把 src(或根目錄)加入 sys.path。因此,import mypkg 時會直接載入 專案目錄下的原始碼。只要修改檔案,下一次執行即能看到最新的行為。

重點:Editable 安裝只影響 開發環境,發布到 PyPI 時仍然需要正式的 sdistwheel,不會把 .pth 檔上傳。

2. setup.cfgpyproject.tomlsetup.py 的差異

近年來 Python 專案越來越傾向使用 PEP 517/518 標準,將建構資訊寫在 pyproject.toml,而非傳統的 setup.pypip install -e 完全支援兩種寫法,只要 pyproject.toml 中宣告了建構後端(如 setuptoolsflitpoetry),pip 會自動呼叫對應的工具完成 editable 安裝。

以下示範兩種常見配置:

方式 主要檔案 範例
傳統 setup.py + setup.cfg setup.py 只保留最小程式碼,設定放在 setup.cfg
PEP 517 pyproject.toml 完全不需要 setup.py,所有設定都在 pyproject.toml

3. 為什麼要使用 -e

  • 即時測試:修改模組即時生效,配合 pytesttox 等測試工具,可省去重新安裝的步驟。
  • 多套件協同開發:在 monorepo 或多子套件的情況下,使用 editable 安裝讓每個子套件都能互相引用最新程式碼。
  • IDE/偵錯友好:大部分 IDE(VS Code、PyCharm)會直接讀取 site-packages,若是 editable 安裝,IDE 能正確定位到原始檔,提供完整的自動完成與除錯資訊。

程式碼範例

以下示範從最簡單的專案結構到進階的 pyproject.toml 配置,讓你一步步掌握 pip install -e 的使用方式。

範例 1:最小專案結構與 setup.py

myproj/
├─ mypkg/
│  ├─ __init__.py
│  └─ core.py
├─ tests/
│  └─ test_core.py
├─ setup.py
└─ README.md

setup.py(最簡化版):

# setup.py
from setuptools import setup, find_packages

setup(
    name="myproj",
    version="0.1.0",
    packages=find_packages(),
    # 讓 pip 知道可以 editable 安裝
    # 這裡不需要額外參數,默認即支援 -e
)

安裝方式(在 myproj 根目錄執行):

pip install -e .

此時,import mypkg.core 會直接載入 myproj/mypkg/core.py,你在 core.py 加入以下程式碼並儲存,即可立刻在 REPL 中看到變化:

# mypkg/core.py
def greet(name: str) -> str:
    """回傳問候字串"""
    return f"Hello, {name}!"

# 測試
if __name__ == "__main__":
    print(greet("World"))

範例 2:使用 setup.cfg 分離設定

myproj/
├─ mypkg/
│  ├─ __init__.py
│  └─ utils.py
├─ setup.cfg
├─ setup.py
└─ README.md

setup.cfg

[metadata]
name = myproj
version = 0.2.0
description = 範例專案,使用 setup.cfg

[options]
packages = find:
python_requires = >=3.8

setup.py(只保留必要的呼叫):

# setup.py
from setuptools import setup

if __name__ == "__main__":
    setup()

安裝指令

pip install -e .

提示:若你只想在開發環境使用 editable 安裝,建議在 requirements-dev.txt 中寫入 -e .,讓 CI/CD 的測試階段自動安裝。

範例 3:PEP 517/518 風格的 pyproject.toml

myproj/
├─ src/
│  └─ mypkg/
│     ├─ __init__.py
│     └─ math.py
├─ tests/
│  └─ test_math.py
└─ pyproject.toml

pyproject.toml(使用 setuptools 作為建構後端):

[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "myproj"
version = "0.3.0"
description = "使用 pyproject.toml 的範例專案"
requires-python = ">=3.9"
dependencies = []

[tool.setuptools.packages.find]
where = ["src"]

安裝指令

pip install -e .

此時 import mypkg.math 會自動從 src/mypkg 讀取,無需在 setup.py 中寫任何程式碼。

範例 4:在 monorepo 中同時 editable 多套件

假設你有兩個子套件 lib_alib_blib_b 依賴 lib_a

repo/
├─ lib_a/
│  ├─ src/
│  │   └─ lib_a/
│  │       └─ __init__.py
│  └─ pyproject.toml
├─ lib_b/
│  ├─ src/
│  │   └─ lib_b/
│  │       └─ __init__.py
│  └─ pyproject.toml
└─ requirements-dev.txt

requirements-dev.txt

-e ./lib_a
-e ./lib_b

執行:

pip install -r requirements-dev.txt

此時 lib_b 內的程式碼若 import lib_a,會直接使用 editable 安裝的 lib_a,即使你同時在兩個套件內部修改,都能即時反映。

範例 5:搭配 pytest 直接測試

在專案根目錄建立 pytest.ini(或 pyproject.toml 中的 [tool.pytest.ini_options]):

# pytest.ini
[pytest]
addopts = -ra -q
testpaths = tests

執行測試:

pytest

因為專案已以 -e 方式安裝,tests 內的 import mypkg.core 會直接載入最新程式碼,無需額外的 PYTHONPATH 設定。


常見陷阱與最佳實踐

陷阱 說明 解決方案或最佳實踐
1. 權限問題 在全域環境使用 pip install -e . 可能需要 sudo,但 sudo 會把檔案安裝在系統路徑,導致後續無法以使用者身分更新。 使用 virtualenv / venv,在隔離環境中安裝 editable 套件,避免權限衝突。
2. src 佈局未正確設定 若專案使用 src/ 目錄,但 setup.cfg/pyproject.toml 沒告訴 setuptools 在哪裡找套件,editable 安裝會失敗。 setup.cfg 加入 <options.packages.find.where = src> 或在 pyproject.toml 中的 [tool.setuptools.packages.find] where = ["src"]
3. 依賴未同步更新 editable 只會把套件本身設為指向原始碼,不會自動安裝 install_requires 中的依賴。 在第一次安裝時執行 pip install -e .[dev](使用 extras)或手動安裝缺少的依賴。
4. 發佈時忘記移除 -e 某些 CI/CD pipeline 直接把 requirements.txt 推上 PyPI,若裡面仍有 -e .,會導致安裝失敗。 分離開發需求(requirements-dev.txt)與正式需求(requirements.txt),確保發佈時不包含 -e
5. 多個同名套件的衝突 在同一環境中同時安裝兩個不同路徑的 editable 套件,且套件名稱相同,會產生衝突。 使用 unique package name,或在不同 virtualenv 中分別安裝。

最佳實踐小結

  1. 永遠在 virtualenv 中使用 -e,保持系統環境乾淨。
  2. -e . 放入 requirements-dev.txt,讓開發者只需一條指令即可安裝全部開發相依。
  3. 使用 src 佈局 搭配正確的 find_packages(where="src"),可避免意外把測試檔案打包進發佈版。
  4. 在 CI 中加入 pip install -e .,確保測試跑的是最新程式碼,且與本機行為一致。
  5. 定期檢查 .pth,若不再需要可手動刪除或使用 pip uninstall 移除套件。

實際應用場景

場景 為什麼適合使用 pip install -e
1. 套件開發者 每次改動都立即可在 REPL、測試或示範腳本中驗證,省去重複打包的時間。
2. 多服務微服務架構 各微服務的共用函式庫(例如 common-utils)可以以 editable 方式安裝,保證所有服務執行的都是同一份最新程式碼。
3. 教學與工作坊 講師只需要一次 pip install -e .,學員即能在自己的筆記本上即時修改範例程式碼,提升互動性。
4. 研究原型 資料科學家常在 Jupyter Notebook 中測試自訂函式庫,editable 安裝讓 Notebook 能即時載入最新的演算法實作。
5. CI/CD 測試管線 在 GitHub Actions、GitLab CI 等環境中,以 pip install -e . 安裝套件,再跑 pytest,可保證測試與開發環境行為一致。

總結

  • pip install -e .開發階段的神器,讓 Python 套件在本機環境中保持「即時」與「可編輯」的狀態。
  • 透過正確的專案結構(src 佈局或 pyproject.toml),配合 setup.cfg / setup.py,即可輕鬆完成 editable 安裝。
  • 注意 權限、依賴、路徑設定 等常見陷阱,並遵循 virtualenv + requirements‑dev.txt 的最佳實踐,能讓專案維護更安全、團隊協作更順暢。
  • 無論是單一套件開發、monorepo 多套件管理,或是教學、研究原型,都能從 pip install -e 中受益,提升開發效率與除錯體驗。

快把這個指令加入你的開發工作流程吧!在下一次改寫程式碼時,你會發現 不需要再重新安裝,而是直接在 Python 直譯器或測試套件中看到最新的變化。祝開發順利 🚀.