Python 安裝筆記

我算 python 新手, 因此這篇筆記只是記錄我的安裝步驟而已.

在閱讀資料的過程中, 第一個想法是工具怎麼這麼多, 真怕把環境搞爛了.

學習目標如下

  1. 我要怎麼管理 python 版本?

  2. 我不希望套件全部都在 python 版本內, 而是要依據專案需求配置.

  3. 套件依賴希望可以類似 package.json 做版控.

Dev Env

簡單介紹我的配置與環境.

  • MacOS

  • Homebrew

  • zsh (with oh my zsh framework)

  • VsCode

大概是寫過 NodeJs, 因此有了 nvm 的概念跟踩過一些環境配置的雷. 而 MacOs 本身就自帶 python2, 若執行了 pip 安裝套件依賴, 我可能會搞不清楚這些 dependencies 到底安裝到什麼神秘空間去了. 環境爛了, 可能也影響了 MacOs 的某些需要依賴 python2 的東西.

因此我的習慣是

  • 盡可能地使用 python 版本控制工具.

  • 盡可能地不要影響電腦的 global 環境.

  • 讓套件跟著專案走, 而不是跟著 python 版本走,

    • 避免專案 A 要用 requests-1 版本,

    • 專案 B 要用 requests-2 版本…

  • 版本好切換操作, 環境不要爆炸

pyenv

pyenv 是用來管理 OS 環境的 Python 版本,

  • 若你是 Java 的開發者可能可以理解為 Sdkman

  • 若你是 node 的開發者可能可以理解為 Nvm

# 用 homebrew 安裝
brew install pyenv

pyenv 配置在 zsh 環境

這幾行會在 ~/.zshrc 裡面添加 PYENV_ROOT 這些環境變數,

還有在 zsh 啟動時執行 pyenv init.

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

安裝完我習慣重新載入 ~/.zshrc , 先驗證一下 ~/.zshrc 有沒有改壞, 然後按照官方建議的重啟 shell 環境.

# 驗證一下有沒有 error, 基本上就能 echo $PYENV_ROOT 這個環境變數了
source ~/.zshrc

# 官方建議的重啟 shell 環境.
exec "$SHELL"

pyenv 常用指令

# pyenv 目前版本
pyenv --version

# 目前安裝的 python 版本
pyenv versions

# 列出可安裝的 python 版本, 實在眼花撩亂啊
pyenv install -l | grep '你要的版本'

# 安裝 Cpython 3.13.0 並且 output 一些額外的資訊
# 安裝完會在 ~/users/yourname/.pyenv/versions 看到你安裝的 python 版本
# 而上面 zshrc 的設定, 會載入 ~/users/yourname/.pyenv/shims 裡面的 bin
pyenv install -v 3.13.0

# 切換 local 版本, 會在當下資料夾產生一個 `.python-version`
# 類似 nvm 的 .nvmrc 裡面只會有一行註記版本號
pyenv local '你要的版本'

# 切換 global 的版本, 也就是在不同的 zsh terminal 都會是這個 python 版本
pyenv global '你要的版本'

# 解除 Cpython 3.13.0
pyenv uninstall 3.13.0

pip

用 pyenv 安裝完 python, 通常就會有 pip 這工具, 我不確定是不是 python bundle?

沒有的話參考 guides

# 確認一下目前運行的 python 環境
pyenv which python
/Users/username/.pyenv/versions/3.13.0/bin/python

# 確認 python3 的 pip (跟 python 版本綁定)
python3 -m pip --version
pip 24.2 from /Users/username/.pyenv/versions/3.13.0/lib/python3.13/site-packages/pip (python 3.13)

# 沒有的話, 執行這個安裝 pip 並升級, 
# -m: 表要以模組形式執行, 這裡是執行 pip 模組
# --upgrade 升級
python3 -m pip install --upgrade pip

pip 的依賴安裝去哪裡了?

NodeJs 的開發者, 應該很容易理解 pip 就類似 pnpm 或是 npm 的工具.

但 pip 可能是 bundle 的關係, 所以都安裝在 python 版本資料夾內

# 安裝 http requests 依賴.
pip install requests

# 確認 requests 安裝到哪裡了
pip show requests

Name: requests
Version: 2.32.3
Summary: Python HTTP for Humans.
Home-page: https://requests.readthedocs.io
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
License: Apache-2.0
# 底下這行, 說明是安裝到 /3.13.0/lib 這個目錄底下...
Location: /Users/username/.pyenv/versions/3.13.0/lib/python3.13/site-packages
# requests 的依賴
Requires: certifi, charset-normalizer, idna, urllib3
Required-by:

那這樣的話可能會有一些問題

  1. 套件依賴無法跟著專案版控,

  2. 套件依賴的版本號, 可能會隨著時間不同, 導致 install 的當下拉到不同的版本.

venv

venv 是用來建立 python 虛擬環境的, 似乎也是 python 的 bundle?

# 進入 project 資料夾
cd your-project

# 會在專案資料夾下產生 .venv 的資料夾, 
# .venv 也可替換成比較容易理解的版號 (.3.13.0)
# 一個專案可以產生多個 venv 環境, 這在測試階段可能很有用.
python3 -m venv .venv

# 在 CLI 啟用 venev 的 python 環境
# 吃的會是執行指令當下指定的 .venv 內的 python3 環境
source .venv/bin/activate

# 也可以改為用 3.13.0 的環境 (A/B testing ?)
# source .3.13.0/bin/activate

# 確認 python 環境
which python3
# 這邊顯示的就不是 pyenv 的 python3 了
/Users/username/projects/your-project/.venv/bin/python3

# 確認 pip 環境
which pip
/Users/username/projects/your-project/.venv/bin/pip

# 安裝 requests
pip install requests

# 確認 requests 安裝位置
pip show requests

Name: requests
Version: 2.32.3
Summary: Python HTTP for Humans.
Home-page: https://requests.readthedocs.io
Author: Kenneth Reitz
Author-email: me@kennethreitz.org
License: Apache-2.0
# 路徑變成專案底下的 .venv/lib/python3.9
Location: /Users/username/projects/your-project/.venv/lib/python3.9/site-packages
Requires: certifi, charset-normalizer, idna, urllib3
Required-by:

# 解除現在 venv 的 python 環境
deactivate

# 確認 python 環境
pyenv which python
/Users/yourname/.pyenv/versions/3.13.0/bin/python3

這樣已經達成我第一個目標, 讓專案有各自的 python 環境. 但也有一些缺點.

  1. .venv / .3.13.0 不會被版控, 內有設定 .gitignore 檔案.

  2. 因為 .venv / .3.13.0 無法被 git pull 就表示, 其他 team member 需要自己安裝, 就有可能安裝到不同的套件版本.

  3. 延伸上面問題, 跑 CI/CD 流程的時候該怎麼辦?

Poetry

安裝依賴 pipx, pipx 類似 nodejs 的 npx 工具, 可以安裝或是直接執行套件來初始專案.

雖然可以透過 pip 安裝 poetry, 但 pip 跟你執行當下的 python 環境 bundle, 透過 pip 安裝的話, 就會在 ~/.pyenv/versions/3.13.0/lib/python3.13/site-packages , 這會導致 python 版本切換而無法使用 poetry, 所以建議還是用 pipx 來安裝 poetry.

# 查詢 poetry
pip show poetry

Name: poetry
Version: 1.8.4
Summary: Python dependency management and packaging made easy.
Home-page: https://python-poetry.org/
Author: Sébastien Eustace
Author-email: sebastien@eustace.io
License: MIT
Location: /Users/yourname/.pyenv/versions/3.13.0/lib/python3.13/site-packages
Requires: build, cachecontrol, cleo, crashtest, dulwich, fastjsonschema, installer, keyring, packaging, pexpect, pkginfo, platformdirs, poetry-core, poetry-plugin-export, pyproject-hooks, requests, requests-toolbelt, shellingham, tomlkit, trove-classifiers, virtualenv, xattr
Required-by: poetry-plugin-export

pipx

# hombrew 安裝
brew install pipx

# 自動設定環境變數, 等同於在 zsh 環境添加 
# export PATH="$PATH:/Users/yourname/.local/bin"
# ~/.local/bin 就是 pipx 工作資料夾
pipx ensurepath

使用上跟 pip 差不多, 更多細節看官方文件, 或是 pipx --help 就可以了.

使用 pip 安裝的套件會位於 ~/.local/pipx/venvs

# 列出本地套件清單, 會顯示下面資訊
pipx list

# 在 ~/.local/pipx/ 裡面有 venvs 的目錄, 還有操作手冊說明
# 執行 list 的時候, 我已經安裝了 poetry.
venvs are in /Users/yourname/.local/pipx/venvs
apps are exposed on your $PATH at /Users/yourname/.local/bin
manual pages are exposed at /Users/yourname/.local/share/man
   package poetry 1.8.4, installed using Python 3.13.0
    - poetry

使用上跟 pip 差不多, 更多細節看官方文件, 或是 pipx --help 就可以了.

install:安裝一個套件
install-all:安裝所有套件
uninject:從現有的虛擬環境中卸載已注入的套件
inject:將套件安裝到現有的虛擬環境中
pin:鎖定指定的套件,防止其被升級
unpin:取消鎖定指定的套件
upgrade:升級一個套件
upgrade-all:升級所有套件。對每個套件運行 pip install -U <pkgname>
upgrade-shared:升級共享庫
uninstall:卸載一個套件
uninstall-all:卸載所有套件
reinstall:重新安裝一個套件
reinstall-all:重新安裝所有套件
list:列出已安裝的套件
interpreter:與由 pipx 管理的解釋器進行交互
run:下載套件的最新版本到臨時虛擬環境中,然後從中運行應用。也兼容本地的 __pypackages__ 目錄(實驗性功能)
runpip:在已存在的 pipx 管理的虛擬環境中運行 pip
ensurepath:確保 pipx 運行所需的目錄已加入到 PATH 環境變量中
environment:列出 pipx 使用的環境變量和路徑
completions:顯示啟用 shell 自動補全功能的說明

在研究 pipx 的東西還有許多細節, 改天有空再整理.

用 pipx 安裝 poetry

pipx install poetry

在 zsh 環境設定指令自動補齊, 我的 zsh 環境有安裝 oh-my-zsh, 所以整理在 plugins 裏面.

mkdir $ZSH_CUSTOM/plugins/poetry
poetry completions zsh > $ZSH_CUSTOM/plugins/poetry/_poetry

安裝完記得到 ~/.zshrc 配置好 plugins.

# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(
  ...
  ...
  poetry
)

poetry 產生專案

poetry new poetry-demo

產生的專案結構如下, 對 python 新手還滿友善的.

其中 pyproject.toml 檔案, 類似 package.json 的感覺, 裡面就是專案資訊, 跟專案套件依賴相關描述了.

# 安裝依賴的前置條件就是要到專案目錄底下
cd python-poetry

# 安裝依賴, pendulum (python 的 local, date, time 處理套件)
poetry add pendulum

然後就爆炸了, 我是 python 新手, 所以就胡亂 google 問 AI.

  • maturing 看起來是 https://github.com/PyO3/maturin 這個用來產生 cargo 專案, 且其中一行描述了 Cargo meta 需要設置在環境變數 PATH 裏面, 我確實沒有.

  • AI 建議我降版, 或是安裝 Cargo.

Package operations: 1 install, 0 updates, 0 removals

  - Installing pendulum (3.0.0): Failed

  ChefBuildError

  Backend subprocess exited when trying to invoke build_wheel

  Running `maturin pep517 build-wheel -i /private/var/folders/7y/khgfhgl11d52pv2x7fk6t8wm0000gn/T/tmpwrk1p383/.venv/bin/python --compatibility off`
  💥 maturin failed
    Caused by: Cargo metadata failed. Do you have cargo in your PATH?
    Caused by: No such file or directory (os error 2)
  Error: command ['maturin', 'pep517', 'build-wheel', '-i', '/private/var/folders/7y/khgfhgl11d52pv2x7fk6t8wm0000gn/T/tmpwrk1p383/.venv/bin/python', '--compatibility', 'off'] returned non-zero exit status 1


  at ~/.local/pipx/venvs/poetry/lib/python3.13/site-packages/poetry/installation/chef.py:164 in _prepare
      160│
      161│                 error = ChefBuildError("\n\n".join(message_parts))
      162│
      163│             if error is not None:
    → 164│                 raise error from None
      165│
      166│             return path
      167│
      168│     def _prepare_sdist(self, archive: Path, destination: Path | None = None) -> Path:

Note: This error originates from the build backend, and is likely not a problem with poetry but with pendulum (3.0.0) not supporting PEP 517 builds. You can verify this by running 'pip wheel --no-cache-dir --use-pep517 "pendulum (==3.0.0)"'.

我在想這可能是個時機不好的測試案例 XD, 索性就放棄官方的 pendulum 案例, 改裝 flask 就成功了.

poetry add flask

測試了一下 pendulum 用 poetry 安裝有許多問題, 但因為太菜了, 暫時沒能力深入學習.

感覺 pendulum 是個生機蓬勃的套件 XD, 有點亂啊.

總結

Python 的環境配置與依賴管理真的是個門檻, 但語法滿容易學習的.

如果是實際專案的話, 應該還是要按照專案規劃配置環境.

但這是我自己學習的紀錄, 我傾向於

  1. 先用 pyenv 安裝管理 OS 層的 python.

  2. 用 pipx 控制管理 OS 層的 python 依賴.

  3. 用 poetry 控制管理專案內的 python 環境與依賴.

Thx and Ref