Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
YouTube Security VideosWelcome to GitHub Copilot Day: the future of agentic engineering(22.09.2026 um 20:00 Uhr)
YouTube Security VideosMicrosoft Mechanics: What Can a Copilot Agent Actually Read?(22.09.2026 um 20:27 Uhr)
Unix & Linux ServerPeppermintOS Is Moving From Xorg to XLibre to Avoid Wayland(22.09.2026 um 19:58 Uhr)
Sicherheitslücken (CVE)USN-8803-1: Sudo vulnerability(22.09.2026 um 16:15 Uhr)
Sichere ProgrammierungClaude Opus 5.5 is now available in GitHub Copilot(22.09.2026 um 19:10 Uhr)
Sichere ProgrammierungColab is now part of your Google AI plan(22.09.2026 um 20:51 Uhr)
Sichere ProgrammierungThe Hidden Production Risks of Third-Party SDKs(22.09.2026 um 20:00 Uhr)
YouTube Security VideosWelcome to GitHub Copilot Day: the future of agentic engineering(22.09.2026 um 20:00 Uhr)
YouTube Security VideosMicrosoft Mechanics: What Can a Copilot Agent Actually Read?(22.09.2026 um 20:27 Uhr)
Unix & Linux ServerPeppermintOS Is Moving From Xorg to XLibre to Avoid Wayland(22.09.2026 um 19:58 Uhr)
Sicherheitslücken (CVE)USN-8803-1: Sudo vulnerability(22.09.2026 um 16:15 Uhr)
Sichere ProgrammierungClaude Opus 5.5 is now available in GitHub Copilot(22.09.2026 um 19:10 Uhr)
Sichere ProgrammierungColab is now part of your Google AI plan(22.09.2026 um 20:51 Uhr)
Sichere ProgrammierungThe Hidden Production Risks of Third-Party SDKs(22.09.2026 um 20:00 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

給 Junior 的 Python 品質工具入門:Ruff 與 Mypy

你的程式碼能跑不代表它沒問題。這兩個工具幫你在「出事之前」就抓到問題。 問題的起點:Python 太自由了 Python 是一個非常「寬容」的語言。它讓你做很多事情,但不會告訴你做錯了: def add(a: int, b: int) -> int: return a + b result = add("hello", "world") # Python 不會報錯,直接跑 print(result) …

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

你的程式碼能跑不代表它沒問題。這兩個工具幫你在「出事之前」就抓到問題。










問題的起點:Python 太自由了



Python 是一個非常「寬容」的語言。它讓你做很多事情,但不會告訴你做錯了:




def add(a: int, b: int) -> int:
return a + b

result = add("hello", "world") # Python 不會報錯,直接跑
print(result) # "helloworld" — 你說要 int,它收到 str,沒人管









import json        # 你 import 了但沒用到,Python 不管
import os # 這個也沒用到,Python 也不管

def process(data ,count): # 逗號前面多了空格,Python 不管
temp = 42 # 定義了變數但沒用,Python 不管
result = data*count
return result






這些問題不會讓程式「爆掉」,但會慢慢腐蝕你的 codebase——直到某天出了 bug,你花了三小時 debug,結果發現只是型別傳錯了。



Ruff 和 Mypy 就是幫你在這些問題變成 bug 之前就抓到它們。









Mypy:型別檢查器






它解決什麼問題?



Python 的 type hint(a: int)只是給人看的註解,執行時完全不檢查。Mypy 是那個真的去檢查的工具






沒有 Mypy 的世界






def get_user_name(user_id: int) -> str:
if user_id <= 0:
return None # 你說回傳 str,卻回傳了 None
return "Alice"

name = get_user_name(1)
print(name.upper()) # 大部分時候沒事
print(get_user_name(-1).upper()) # 💥 AttributeError: 'NoneType' has no attribute 'upper'
# 半夜三點,上線才爆






Python 不會警告你,直到程式跑到那一行才炸掉。






有 Mypy 的世界






$ mypy your_code.py
your_code.py:3: error: Incompatible return value type (got "None", expected "str")






程式還沒跑就告訴你哪裡錯了。 你可以這樣修:




def get_user_name(user_id: int) -> str | None:  # 明確宣告可能回傳 None
if user_id <= 0:
return None
return "Alice"

name = get_user_name(1)
if name is not None: # Mypy 會強制你處理 None 的情況
print(name.upper())









Mypy 能抓到的錯誤






# ① 型別不匹配
def add(a: int, b: int) -> int:
return a + b

add("hello", "world")
# mypy: Argument 1 has incompatible type "str"; expected "int"


# ② 忘記處理 None
def find_user(user_id: int) -> dict | None:
...

user = find_user(1)
print(user["name"])
# mypy: Value of type "dict | None" is not indexable


# ③ 回傳值型別錯誤
def calculate_price(quantity: int, unit_price: float) -> int:
return quantity * unit_price # 回傳 float,但你說回傳 int
# mypy: Incompatible return value type (got "float", expected "int")


# ④ 缺少回傳值
def validate(value: int) -> bool:
if value > 0:
return True
# 忘了 else 的情況,隱式回傳 None
# mypy: Missing return statement


# ⑤ 存取不存在的屬性
class User:
def __init__(self, name: str):
self.name = name

user = User("Alice")
print(user.email)
# mypy: "User" has no attribute "email"









怎麼用






# 安裝
pip install mypy

# 檢查單一檔案
mypy your_code.py

# 檢查整個專案
mypy src/

# 嚴格模式(所有函式都必須有 type annotation)
mypy --strict src/









設定(在 pyproject.toml)






[tool.mypy]
python_version = "3.12"
strict = true # 開啟嚴格模式
warn_return_any = true # 回傳 Any 型別時警告
warn_unused_ignores = true # 不必要的 type: ignore 會警告
disallow_untyped_defs = true # 所有函式都必須有型別標註

# 如果某些第三方套件沒有 type stub,可以個別忽略
[[tool.mypy.overrides]]
module = "some_untyped_library.*"
ignore_missing_imports = true












Ruff:超快的 Linter + Formatter






它解決什麼問題?



在 Ruff 出現之前,你需要裝好幾個工具才能做到完整的程式碼品質檢查:
















































工具 做什麼 速度
pylint 找 bug 和風格問題
flake8 找風格違規 中等
isort 自動排序 import 中等
black 自動格式化程式碼 中等
pyflakes 找未使用的變數/import 中等
pyupgrade 自動升級舊語法 中等
bandit 找安全性問題 中等


Ruff 用 Rust 寫成,把以上所有工具的功能合成一個,而且快 10~100 倍。大型專案裡 pylint 跑好幾分鐘的事情,Ruff 幾秒鐘就完成。






Ruff 當 Linter:幫你找問題






# bad_code.py
import os
import json # ← 沒用到

def calculate(x ,y): # ← 逗號前有多餘空格
temp = 42 # ← 變數定義了但沒用到
result = x+y
return result

class user: # ← class 名稱應該用 CapWords
pass









$ ruff check bad_code.py
bad_code.py:2:8: F401 `json` imported but unused
bad_code.py:4:18: E231 missing whitespace after ','
bad_code.py:5:5: F841 local variable `temp` is assigned but never used
bad_code.py:9:7: N801 class `user` should use CapWords convention
Found 4 errors.






自動修復能修的:




$ ruff check --fix bad_code.py
Found 4 errors (2 fixed, 2 remaining).
# 自動移除沒用到的 import、修正空格
# class 命名和未使用變數需要你自己改(因為 ruff 不確定你的意圖)









Ruff 當 Formatter:幫你統一風格






# 格式化前
def foo( a,b, c ):
return {"key":a,"key2": b,"key3":c}

x=[1,2,
3,4,5]









$ ruff format bad_code.py
1 file reformatted









# 格式化後
def foo(a, b, c):
return {"key": a, "key2": b, "key3": c}

x = [1, 2, 3, 4, 5]









Ruff 能抓到的常見問題






# F401: 未使用的 import
import os # 你沒用到 os,刪掉

# F841: 未使用的變數
result = compute() # 你算了但沒用到

# E711: 用 == 比較 None
if value == None: # 應該用 is None

# B006: Mutable default argument
def foo(items=[]): # 應該用 None

# UP035: 過時的 import
from typing import List # Python 3.9+ 直接用 list

# N801: class 命名不符合 CapWords
class my_class: # 應該是 MyClass

# I001: import 沒有按照順序排列
import os
import abc # abc 應該在 os 前面

# S101: 在非測試程式碼中使用 assert(安全性問題)
assert user.is_admin # 用 raise 而不是 assert









怎麼用






# 安裝
pip install ruff

# Lint:找出問題
ruff check .

# Lint + 自動修復
ruff check --fix .

# Format:自動統一風格
ruff format .

# 查看會改什麼(不實際修改)
ruff format --check .









設定(在 pyproject.toml)






[tool.ruff]
line-length = 80 # 每行最長 80 字元
target-version = "py312" # 目標 Python 版本

[tool.ruff.lint]
select = [
"E", # pycodestyle errors(空格、縮排等)
"F", # pyflakes(未使用的 import、變數等)
"I", # isort(import 排序)
"N", # pep8-naming(命名規範)
"UP", # pyupgrade(用新語法取代舊的)
"B", # flake8-bugbear(常見 bug 模式)
"S", # bandit(安全性問題)
"SIM", # flake8-simplify(可簡化的程式碼)
]

# 想要更嚴格?直接全開
# select = ["ALL"]

ignore = [
"S101", # 允許在測試中使用 assert
]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["S101"] # 測試檔案允許 assert












Ruff vs Mypy:各管什麼?



這兩個工具是互補的,不是替代關係:




               Ruff                          Mypy
┌──────────────────┐ ┌──────────────────┐
│ 風格和格式 │ │ 型別正確性 │
│ ─────────────── │ │ ─────────────── │
│ ✓ import 排序 │ │ ✓ 型別不匹配 │
│ ✓ 未使用的變數 │ │ ✓ 忘記處理 None │
│ ✓ 命名規範 │ │ ✓ 回傳型別錯誤 │
│ ✓ 空格/縮排 │ │ ✓ 屬性不存在 │
│ ✓ 安全性問題 │ │ ✓ 參數型別錯誤 │
│ ✓ 過時語法 │ │ │
└──────────────────┘ └──────────────────┘
看得整不整齊 用得對不對






一個實際的例子:




import json                        # ← Ruff 會抓(F401: 未使用的 import)

def add(a: int, b: int) -> int:
return a + b

result = add("hello", "world") # ← Mypy 會抓(型別不匹配)
temp = 42 # ← Ruff 會抓(F841: 未使用的變數)






兩個都用,才是完整的品質檢查。









整合 Git Pre-commit Hook






為什麼需要?



你可以手動跑 ruff checkmypy,但你會忘。特別是趕進度的時候。



Pre-commit hook 的意思是:每次你執行 git commit,自動先跑這些檢查。沒通過就不讓你 commit。




git commit

├── ① ruff check(lint) → 有未使用的 import?❌ 擋住
├── ② ruff format(格式化) → 格式不對?自動修好,要你重新 commit
└── ③ mypy(型別檢查) → 型別錯誤?❌ 擋住

✅ 全部通過 → commit 成功






這樣不管你多趕,品質都有底線。






Step 1:安裝 pre-commit






pip install pre-commit









Step 2:建立 .pre-commit-config.yaml



在你的專案根目錄建立這個檔案:




# .pre-commit-config.yaml
repos:
# Ruff:Lint + Format
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.1 # 用最新版本,可以跑 `pre-commit autoupdate` 自動更新
hooks:
# 先跑 linter(並自動修復能修的問題)
- id: ruff-check
args: [--fix]
# 再跑 formatter
- id: ruff-format

# Mypy:型別檢查
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.15.0 # 用最新版本
hooks:
- id: mypy
args: [--strict, --ignore-missing-imports]
# 如果你的程式碼用到第三方套件的型別,加在這裡
additional_dependencies:
- pydantic
- types-requests






注意順序:ruff-check(帶 --fix)要在 ruff-format 前面。 因為 lint 修復可能產生需要再格式化的程式碼。






Step 3:啟用 hook






# 安裝 hook 到 .git/hooks/
pre-commit install

# 完成!之後每次 git commit 都會自動跑









Step 4:試跑看看






# 手動對所有檔案跑一次(建議第一次設定時執行)
pre-commit run --all-files






輸出會長這樣:




ruff-check...............................................................Passed
ruff-format..............................................................Passed
mypy.....................................................................Failed
- hook id: mypy
- exit code: 1

src/main.py:15: error: Incompatible return value type (got "None", expected "str")






Mypy 沒通過,commit 被擋住。你修好之後重新 git addgit commit 就行了。






實際開發的流程






# 1. 寫程式碼(或讓 AI 幫你寫)
# 2. git add
git add .

# 3. git commit — pre-commit 自動跑
git commit -m "feat: add user authentication"

# 情況 A:全部通過 ✅
# → commit 成功

# 情況 B:ruff format 自動修了格式 ⚠️
# → commit 失敗,但檔案已經被修好了
# → 重新 git add . && git commit 就好

# 情況 C:mypy 找到型別錯誤 ❌
# → commit 失敗,你需要手動修
# → 修好後重新 git add . && git commit









完整的 pyproject.toml 設定範例






# pyproject.toml

[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"

# ── Ruff 設定 ──
[tool.ruff]
line-length = 80
target-version = "py312"

[tool.ruff.lint]
select = [
"E", # pycodestyle
"F", # pyflakes
"I", # isort
"N", # naming
"UP", # pyupgrade
"B", # bugbear
"S", # bandit(安全性)
"SIM", # simplify
]

[tool.ruff.lint.per-file-ignores]
"tests/*" = ["S101"] # 測試允許 assert

# ── Mypy 設定 ──
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_ignores = true

[[tool.mypy.overrides]]
module = "some_untyped_library.*"
ignore_missing_imports = true












常見問題






「我趕死線了,能不能跳過 hook?」






git commit --no-verify -m "hotfix: emergency patch"






--no-verify 會跳過所有 pre-commit hook。但這應該是非常罕見的例外,不是常態。如果你經常需要跳過,代表你的規則可能太嚴,或你需要花時間修掉累積的問題。






「Mypy 對第三方套件報錯怎麼辦?」



有些套件沒有提供型別資訊,mypy 會報 import 錯誤。兩種解法:




# 方法 1:安裝型別 stub
pip install types-requests types-redis types-PyYAML

# 方法 2:在 pyproject.toml 裡忽略特定套件









[[tool.mypy.overrides]]
module = "some_library.*"
ignore_missing_imports = true









「Ruff 跟 Black 要選哪個?」



2025 年的答案:選 Ruff。 它的 formatter 跟 Black 幾乎 100% 相容,但更快,而且你不需要額外裝一個工具。如果你的專案已經在用 Black,遷移到 Ruff 也很簡單。






「hook 跑太慢怎麼辦?」



Ruff 是 Rust 寫的,基本上不會慢。Mypy 可能會慢一點,尤其是第一次跑。可以用 mypy daemon 加速:




# 用 dmypy 做增量檢查,只檢查你改過的檔案
dmypy run -- src/












一句話總結




























工具 做什麼 比喻
Ruff 風格、格式、常見錯誤 校稿編輯:錯字、格式、排版
Mypy 型別正確性 邏輯審查:你說的和你做的有沒有一致
Pre-commit 自動化執行 門禁系統:不通過就不讓你進門


三個搭在一起,你的程式碼品質就有了自動化的底線——不管是你寫的、同事寫的、還是 AI 寫的,都必須通過同樣的品質關卡才能進入 codebase。

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten 給 Junior 的 Python 品質工具入門:Ruff 與 Mypy

Thematisch verwandte Begriffe: Junior, Python, 品質工具入門Ruff, Mypy · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-77258 | MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian pro…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick