Ruff 完整教學 2026:4.9 萬星 Python 最速 Linter 與 Formatter,從安裝、pyproject.toml 設定到 pre-commit 與 GitHub Actions 實戰

Ruff 是 Astral 用 Rust 寫的 Python linter 與 formatter,速度比 Flake8、Black 快 10-100 倍,一個工具就能取代 Flake8、isort、Black、pyupgrade、autoflake 整套程式碼品質工具鏈。這篇完整教學帶你從安裝、第一個指令、pyproject.toml 設定、規則速查,到 pre-commit 與 GitHub Actions 的 CI/CD 實戰整合,全部指令皆經實測驗證。

  • Dennis
  • 8 分鐘閱讀
Ruff 完整教學 2026:4.9 萬星 Python 最速 Linter 與 Formatter,從安裝、pyproject.toml 設定到 pre-commit 與 GitHub Actions 實戰

Ruff 是 Astral 用 Rust 寫的 Python linter 與 formatter,速度比 Flake8、Black 快 10-100 倍,用一個指令就能取代 Flake8(加幾十個外掛)、isort、Black、pyupgrade、autoflake 這整套 Python 程式碼品質工具鏈。截至 2026 年 8 月,Ruff 在 GitHub 已累積 49,000+ 星,FastAPI、Hugging Face、Pandas、Apache Airflow、PyTorch 等知名專案都在用它。

一句話結論

Ruff = Python 開發者的「一條龍程式碼品質工具」ruff check 做靜態檢查(找出未使用的 import、潛在 bug、資安風險),ruff format 做自動排版,兩者都是毫秒級完成。它用 Rust 重寫了 Flake8 生態系的 900+ 條規則,內建快取與自動修復(--fix),設定全寫在 pyproject.toml 裡,是 2026 年 Python 專案最值得第一個安裝的開發工具。

為什麼 2026 的 Python 開發者都在用 Ruff?

傳統 Python 專案的程式碼品質工具鏈是這樣的:Flake8 檢查風格、Black 排版、isort 排 import、pyupgrade 升級語法、autoflake 刪冗餘程式碼——五個工具、五套設定、五倍等待時間。Ruff 把這五件事(還有更多)合併成一個二進位檔:

  • 快 10-100 倍:Dagster 共同創辦人 Nick Schrock 實測:pylint 掃 25 萬行的 dagster 程式庫要 2.5 分鐘,Ruff 掃整個 codebase 只要 0.4 秒
  • 📦 內建快取:不會重複分析沒改動的檔案,愈掃愈快
  • 🔧 自動修復ruff check --fix 自動刪未使用的 import、自動加未來註解,不用動手
  • 📏 900+ 條規則:原生用 Rust 重寫 Flake8 熱門外掛(bugbear、bandit 資安規則、pytest-style 等)
  • 🤝 Drop-in 相容:跟 Flake8、isort、Black 的既有規則相容,遷移成本極低
  • 🌎 Monorepo 友善:支援階層式設定,每個子專案可以覆蓋父層設定

安裝 Ruff(5 種方式任選)

Ruff 目前最新版為 0.16.4,支援 Python 3.14。如果你已經在用 uv(Astral 的另一個明星專案),直接一行搞定:

# ✅ 推薦:用 uv 全域安裝
uv tool install ruff@latest

# 或當成專案的開發依賴
uv add --dev ruff

# 傳統方式
pip install ruff
pipx install ruff

# 獨立安裝器(macOS / Linux)
curl -LsSf https://astral.sh/ruff/install.sh | sh

# macOS 也可以用 Homebrew
brew install ruff

不想安裝的話,還能用 uvx ruff@0.16.4 check 直接跑,用完即丟。

第一個指令:check 與 format

安裝完立刻就能用,零設定

# 靜態檢查目前目錄(含子目錄)的所有 .py 檔
ruff check

# 自動修復所有能自動修的問題(例如刪未使用的 import)
ruff check --fix

# 只檢查某個檔案或資料夾
ruff check src/ app/main.py

# 自動排版(等價於 Black 的格式規範)
ruff format

# 排完版再檢查一遍(常用組合)
ruff check --fix && ruff format

Ruff 0.16 的預設規則集就涵蓋了 40+ 個規則類別(含 flake8-bugbear 的 B、bandit 的 S 資安規則、pyupgrade 的 UP、isort 的 I 排序),也就是說你什麼都不設定,它已經能抓出一堆常見問題——最典型的就是「未使用的 import」。

pyproject.toml 完整設定實戰

Ruff 的設定寫在 pyproject.toml(或獨立的 ruff.toml / .ruff.toml),用 [tool.ruff] 前綴。這是一份適合中型專案的實用設定:

[tool.ruff]
# 一行最多 88 字元(跟 Black 預設一致)
line-length = 88
# 假設專案最低支援 Python 3.10
target-version = "py310"

[tool.ruff.lint]
# 明確啟用規則類別:E=pycodestyle 錯誤、F=pyflakes、
# I=isort 排序、UP=pyupgrade、B=bugbear、SIM=簡化、S=bandit 資安
select = ["E", "F", "I", "UP", "B", "SIM", "S", "RUF"]
# 忽略特定規則(例如允許 print 除錯)
ignore = ["S101"]  # assert 用於測試沒關係

# 某些檔案放寬規則(例如 __init__.py 允許未使用的 import)
[tool.ruff.lint.per-file-ignores]
"__init__.py" = ["F401"]

[tool.ruff.format]
# 跟 Black 一致:雙引號、空格縮排
quote-style = "double"
indent-style = "space"

規則代碼速查表

Ruff 的規則代碼沿用 Flake8 生態的命名,看到代碼就知道是哪一類:

代碼來源檢查什麼範例
FPyflakes未使用的 import、未定義變數F401 未使用 import
E / WpycodestylePEP 8 風格錯誤 / 警告E501 行太長
Iisortimport 排序I001 import 未排序
UPpyupgrade升級到新版 Python 語法UP038 改用 X | Y 型別
Bflake8-bugbear常見潛在 bugB006 可變預設參數
SIMflake8-simplify程式碼簡化SIM108 改用三元運算子
Sflake8-bandit資安風險S101 使用 assert
Npep8-naming命名慣例N802 函式名稱大小寫
C4flake8-comprehensions改用 comprehensionsC400 不必要的 list()
ANNflake8-annotations型別註解完整性ANN201 缺回傳型別
T20flake8-print偵測 printT201 程式碼裡有 print
RUFRuff 專屬Ruff 自己的規則RUF001 混淆字元

從 Flake8 + Black + isort 遷移過來

舊工具用戶不用擔心:Ruff 就是設計來當 drop-in 替代品的。比較如下:

項目Flake8 + Black + isort + pyupgradeRuff
工具數量4+ 個(各配一套設定)1 個
掃描 25 萬行程式碼分鐘級0.4 秒
自動修復部分(autoflake 等)--fix 內建
設定檔分散多檔統一 pyproject.toml
資安規則(bandit)需另外裝外掛✅ 內建 S 類別
型別註解檢查(ANN)需另外裝外掛✅ 內建
快取✅ 內建

遷移三步驟:① pip uninstall flake8 black isort pyupgrade autoflake ② 安裝 Ruff ③ 把 .flake8black.tomlisort.cfg 的設定合併進 pyproject.toml[tool.ruff]。格式部分,Ruff 的 formatter 就是「Black 相容」的(兩者都基於 88 字元、雙引號、magic trailing comma 原則),排版結果幾乎一致。

pre-commit 整合(在地 commit 前就把關)

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.16.4
    hooks:
      - id: ruff-check
        args: [--fix]
      - id: ruff-format

這樣每次 git commit 都會先跑 lint+排版,不合格的檔案自動被擋下或修好,壞程式碼進不了 git 歷史

GitHub Actions CI(遠端也把關)

# .github/workflows/ruff.yml
name: Ruff
on: [push, pull_request]
jobs:
  ruff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: astral-sh/ruff-action@v3

官方 ruff-action 會自動安裝最新版 Ruff 並執行 ruff check,任何違反規則的 PR 都會被紅燈擋下。

VS Code 整合

安裝官方擴充套件 Ruff(由 Astral 維護),即可獲得:

  • 輸入時即時顯示 lint 錯誤(紅色波浪線)
  • Shift+Alt+F 直接格式化
  • 儲存時自動修復(editor.codeActionsOnSave 設定)
  • 內建 Ruff Language Server(ruff server),比舊版 ruff-lsp 更快
// .vscode/settings.json
{
  "[python]": {
    "editor.defaultFormatter": "charliermarsh.ruff",
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.fixAll.ruff": "explicit"
    }
  }
}

進階技巧

  1. Preview 模式[tool.ruff.lint] preview = true(或 ruff check --preview)可搶先啟用尚未穩定的新規則。
  2. Monorepo 階層設定:根目錄放一份設定,子專案用各自的 ruff.toml 覆蓋部分規則,Ruff 會自動級聯套用。
  3. 只看差異ruff check --diff 預覽修改內容;--statistics 統計各規則觸發次數。
  4. 與型別檢查器分工:Ruff 管「風格與明顯 bug」,型別檢查交給 Ty 或 mypy——兩者不衝突,可以一起用。
flowchart LR
    A[寫程式] --> B[ruff check<br/>靜態檢查 + --fix 自動修復]
    B --> C[ruff format<br/>自動排版]
    C --> D{pre-commit<br/>檢查是否通過}
    D -->|通過| E[git commit]
    D -->|不通過| A
    E --> F[GitHub Actions<br/>ruff-action 再驗一次]
    F -->|通過| G[CI 綠燈 ✅]

實戰:把一包「髒程式碼」交給 Ruff

假設你接手一個別人寫的爛專案,檔案長這樣:

import os
import json
from datetime import datetime

def get_user_data(user_id):
    # fetch user data from db
    data = fetch_from_db(user_id)
    if data == None:
        return {}
    else:
        result = dict()
        for key in data.keys():
            result[key] = data[key]
        return result

def save_report(rows):
    f = open("report.csv", "w")
    f.write("id,name\n")
    for row in rows:
        f.write(f"{row['id']},{row['name']}\n")
    f.close()

執行 ruff check .,Ruff 一口氣抓到這些問題:

app.py:1:8: F401 [*] `os` imported but unused
app.py:3:1: I001 [*] Import block is unformatted
app.py:8:12: E711 Comparison to `None` should be `cond is None`
app.py:10:9: SIM108 [*] Use a ternary operator instead of if-else
app.py:11:16: C416 [*] Unnecessary `dict` comprehension
app.py:16:9: SIM115 Use a context manager for opening files
app.py:16:14: S108 [*] Probable insecure usage of temporary file

接著下 ruff check --fix && ruff format,幾毫秒內全部自動修好:未使用的 os 被刪掉、import 排好序、== None 改成 is None、if-else 變三元運算子、dict comprehension 簡化。剩下 SIM115(建議改用 with open(...))這種需要人工判斷的,Ruff 會留著提醒你,不會亂改你的邏輯。

這就是 Ruff 的日常:機械性問題它全包,需要判斷力的留給人類工程師。

誰在用 Ruff?

Ruff 的採用名單幾乎是 Python 界的「全明星隊」:FastAPI、Hugging Face(Transformers/Datasets/Diffusers)、Pandas、SciPy、Apache Airflow、Apache Superset、PyTorch、JAX、pytest、Streamlit、LangChain、LlamaIndex、Gradio、Home Assistant、Netflix Dispatch、Microsoft Semantic Kernel……連 Poetry、Pylint、Mypy 這些「被取代的對象」自己都在用 Ruff 檢查自己的程式碼。如果你的專案還沒有 Ruff,加入他們只是時間問題。

常見問題

Q:Ruff 跟 Black 排版會打架嗎? 不會。Ruff 的 formatter 就是相容 Black 的設計(同為 88 字元、雙引號、magic trailing comma),大部分專案可直接替換。極少數邊界案例可參考官方 FAQ 的差異清單。

Q:Ruff 能取代 mypy 嗎? 不能。Ruff 不做型別推斷,型別檢查請交給 Ty / mypy。Ruff 的 ANN 規則可以「要求」你寫型別註解,但真正驗證型別是另一回事。

Q:團隊不想用 Black 風格怎麼辦? Ruff 支援設定 quote-style = "single"line-length 等參數調整排版風格,也可以只關掉 formatter、只用 linter(ruff check 單獨存在)。

Q:Ruff 快是真的假的? 真的。Bokeh 共同創辦人、Conda 原作者 Bryan Van de Ven 實測:「Ruff 比 flake8 快約 150-200 倍,掃整個 repo 約 0.2 秒(原本約 20 秒),快到我把牠直接掛成 commit hook。」

延伸閱讀

資料來源

📬 訂閱 most.tw 電子報

每週精選 AI 工具教學與技術乾貨,直接送到你的信箱。免費、隨時可退訂。

💬 有問題想討論?加 LINE 聯絡我

歡迎透過 LINE 官方帳號直接留言,我會盡快回覆你的問題。

加入 LINE 好友