python-anti-patterns by wshobson/agents
npx skills add https://github.com/wshobson/agents --skill python-anti-patterns一份关于 Python 代码中常见错误和反模式的参考检查清单。在最终确定实现之前进行审查,以便及早发现问题。
注意: 此技能侧重于应避免的事项。关于积极模式和架构的指导,请参阅 python-design-patterns 技能。
# 反面示例:超时逻辑到处重复
def fetch_user(user_id):
try:
return requests.get(url, timeout=30)
except Timeout:
logger.warning("Timeout fetching user")
return None
def fetch_orders(user_id):
try:
return requests.get(url, timeout=30)
except Timeout:
logger.warning("Timeout fetching orders")
return None
修复方法: 集中到装饰器或客户端包装器中。
# 正面示例:集中化的重试逻辑
@retry(stop=stop_after_attempt(3), wait=wait_exponential())
def http_get(url: str) -> Response:
return requests.get(url, timeout=30)
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
# 反面示例:在多个层级进行重试
@retry(max_attempts=3) # 应用层重试
def call_service():
return client.request() # 客户端也配置了重试!
修复方法: 仅在一个层级进行重试。了解基础设施的重试行为。
# 反面示例:代码中包含密钥和配置
DB_HOST = "prod-db.example.com"
API_KEY = "sk-12345"
def connect():
return psycopg.connect(f"host={DB_HOST}...")
修复方法: 使用环境变量和类型化设置。
# 正面示例
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
db_host: str = Field(alias="DB_HOST")
api_key: str = Field(alias="API_KEY")
settings = Settings()
# 反面示例:将 ORM 模型泄露给 API
@app.get("/users/{id}")
def get_user(id: str) -> UserModel: # SQLAlchemy 模型
return db.query(UserModel).get(id)
修复方法: 使用 DTO/响应模型。
# 正面示例
@app.get("/users/{id}")
def get_user(id: str) -> UserResponse:
user = db.query(UserModel).get(id)
return UserResponse.from_orm(user)
# 反面示例:业务逻辑中嵌入 SQL
def calculate_discount(user_id: str) -> float:
user = db.query("SELECT * FROM users WHERE id = ?", user_id)
orders = db.query("SELECT * FROM orders WHERE user_id = ?", user_id)
# 业务逻辑与数据访问混合
if len(orders) > 10:
return 0.15
return 0.0
修复方法: 仓储模式。保持业务逻辑纯净。
# 正面示例
def calculate_discount(user: User, orders: list[Order]) -> float:
# 纯净的业务逻辑,易于测试
if len(orders) > 10:
return 0.15
return 0.0
# 反面示例:吞掉所有异常
try:
process()
except Exception:
pass # 静默失败 - 错误被永远隐藏
修复方法: 捕获特定异常。适当记录或处理。
# 正面示例
try:
process()
except ConnectionError as e:
logger.warning("Connection failed, will retry", error=str(e))
raise
except ValueError as e:
logger.error("Invalid input", error=str(e))
raise BadRequestError(str(e))
# 反面示例:在第一个错误处停止
def process_batch(items):
results = []
for item in items:
result = process(item) # 出错时抛出异常 - 批次处理中止
results.append(result)
return results
修复方法: 同时捕获成功和失败。
# 正面示例
def process_batch(items) -> BatchResult:
succeeded = {}
failed = {}
for idx, item in enumerate(items):
try:
succeeded[idx] = process(item)
except Exception as e:
failed[idx] = e
return BatchResult(succeeded, failed)
# 反面示例:没有验证
def create_user(data: dict):
return User(**data) # 输入错误时,代码深处会崩溃
修复方法: 在 API 边界尽早验证。
# 正面示例
def create_user(data: dict) -> User:
validated = CreateUserInput.model_validate(data)
return User.from_input(validated)
# 反面示例:文件从未关闭
def read_file(path):
f = open(path)
return f.read() # 如果这里抛出异常怎么办?
修复方法: 使用上下文管理器。
# 正面示例
def read_file(path):
with open(path) as f:
return f.read()
# 反面示例:阻塞整个事件循环
async def fetch_data():
time.sleep(1) # 阻塞一切!
response = requests.get(url) # 同样阻塞!
修复方法: 使用异步原生库。
# 正面示例
async def fetch_data():
await asyncio.sleep(1)
async with httpx.AsyncClient() as client:
response = await client.get(url)
# 反面示例:没有类型
def process(data):
return data["value"] * 2
修复方法: 为所有公共函数添加注解。
# 正面示例
def process(data: dict[str, int]) -> int:
return data["value"] * 2
# 反面示例:没有类型参数的通用列表
def get_users() -> list:
...
修复方法: 使用类型参数。
# 正面示例
def get_users() -> list[User]:
...
# 反面示例:只测试成功情况
def test_create_user():
user = service.create_user(valid_data)
assert user.id is not None
修复方法: 测试错误条件和边界情况。
# 正面示例
def test_create_user_success():
user = service.create_user(valid_data)
assert user.id is not None
def test_create_user_invalid_email():
with pytest.raises(ValueError, match="Invalid email"):
service.create_user(invalid_email_data)
def test_create_user_duplicate_email():
service.create_user(valid_data)
with pytest.raises(ConflictError):
service.create_user(valid_data)
# 反面示例:模拟所有东西
def test_user_service():
mock_repo = Mock()
mock_cache = Mock()
mock_logger = Mock()
mock_metrics = Mock()
# 测试没有验证真实行为
修复方法: 对关键路径使用集成测试。仅模拟外部服务。
在最终确定代码之前,请验证:
except Exception: pass| 反模式 | 修复方法 |
|---|---|
| 分散的重试逻辑 | 集中化的装饰器 |
| 硬编码配置 | 环境变量 + pydantic-settings |
| 暴露 ORM 模型 | DTO/响应模式 |
| 混合 I/O + 逻辑 | 仓储模式 |
| 空泛的 except | 捕获特定异常 |
| 批次处理因错误停止 | 返回包含成功/失败的 BatchResult |
| 没有验证 | 使用 Pydantic 在边界处验证 |
| 未关闭的资源 | 上下文管理器 |
| 异步中的阻塞 | 异步原生库 |
| 缺少类型 | 为所有公共 API 添加类型注解 |
| 仅测试成功路径 | 测试错误和边界情况 |
每周安装量
3.3K
仓库
GitHub 星标数
32.2K
首次出现
Jan 30, 2026
安全审计
安装于
opencode2.7K
gemini-cli2.7K
codex2.7K
claude-code2.4K
github-copilot2.4K
cursor2.4K
A reference checklist of common mistakes and anti-patterns in Python code. Review this before finalizing implementations to catch issues early.
Note: This skill focuses on what to avoid. For guidance on positive patterns and architecture, see the python-design-patterns skill.
# BAD: Timeout logic duplicated everywhere
def fetch_user(user_id):
try:
return requests.get(url, timeout=30)
except Timeout:
logger.warning("Timeout fetching user")
return None
def fetch_orders(user_id):
try:
return requests.get(url, timeout=30)
except Timeout:
logger.warning("Timeout fetching orders")
return None
Fix: Centralize in decorators or client wrappers.
# GOOD: Centralized retry logic
@retry(stop=stop_after_attempt(3), wait=wait_exponential())
def http_get(url: str) -> Response:
return requests.get(url, timeout=30)
# BAD: Retrying at multiple layers
@retry(max_attempts=3) # Application retry
def call_service():
return client.request() # Client also has retry configured!
Fix: Retry at one layer only. Know your infrastructure's retry behavior.
# BAD: Secrets and config in code
DB_HOST = "prod-db.example.com"
API_KEY = "sk-12345"
def connect():
return psycopg.connect(f"host={DB_HOST}...")
Fix: Use environment variables with typed settings.
# GOOD
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
db_host: str = Field(alias="DB_HOST")
api_key: str = Field(alias="API_KEY")
settings = Settings()
# BAD: Leaking ORM model to API
@app.get("/users/{id}")
def get_user(id: str) -> UserModel: # SQLAlchemy model
return db.query(UserModel).get(id)
Fix: Use DTOs/response models.
# GOOD
@app.get("/users/{id}")
def get_user(id: str) -> UserResponse:
user = db.query(UserModel).get(id)
return UserResponse.from_orm(user)
# BAD: SQL embedded in business logic
def calculate_discount(user_id: str) -> float:
user = db.query("SELECT * FROM users WHERE id = ?", user_id)
orders = db.query("SELECT * FROM orders WHERE user_id = ?", user_id)
# Business logic mixed with data access
if len(orders) > 10:
return 0.15
return 0.0
Fix: Repository pattern. Keep business logic pure.
# GOOD
def calculate_discount(user: User, orders: list[Order]) -> float:
# Pure business logic, easily testable
if len(orders) > 10:
return 0.15
return 0.0
# BAD: Swallowing all exceptions
try:
process()
except Exception:
pass # Silent failure - bugs hidden forever
Fix: Catch specific exceptions. Log or handle appropriately.
# GOOD
try:
process()
except ConnectionError as e:
logger.warning("Connection failed, will retry", error=str(e))
raise
except ValueError as e:
logger.error("Invalid input", error=str(e))
raise BadRequestError(str(e))
# BAD: Stops on first error
def process_batch(items):
results = []
for item in items:
result = process(item) # Raises on error - batch aborted
results.append(result)
return results
Fix: Capture both successes and failures.
# GOOD
def process_batch(items) -> BatchResult:
succeeded = {}
failed = {}
for idx, item in enumerate(items):
try:
succeeded[idx] = process(item)
except Exception as e:
failed[idx] = e
return BatchResult(succeeded, failed)
# BAD: No validation
def create_user(data: dict):
return User(**data) # Crashes deep in code on bad input
Fix: Validate early at API boundaries.
# GOOD
def create_user(data: dict) -> User:
validated = CreateUserInput.model_validate(data)
return User.from_input(validated)
# BAD: File never closed
def read_file(path):
f = open(path)
return f.read() # What if this raises?
Fix: Use context managers.
# GOOD
def read_file(path):
with open(path) as f:
return f.read()
# BAD: Blocks the entire event loop
async def fetch_data():
time.sleep(1) # Blocks everything!
response = requests.get(url) # Also blocks!
Fix: Use async-native libraries.
# GOOD
async def fetch_data():
await asyncio.sleep(1)
async with httpx.AsyncClient() as client:
response = await client.get(url)
# BAD: No types
def process(data):
return data["value"] * 2
Fix: Annotate all public functions.
# GOOD
def process(data: dict[str, int]) -> int:
return data["value"] * 2
# BAD: Generic list without type parameter
def get_users() -> list:
...
Fix: Use type parameters.
# GOOD
def get_users() -> list[User]:
...
# BAD: Only tests success case
def test_create_user():
user = service.create_user(valid_data)
assert user.id is not None
Fix: Test error conditions and edge cases.
# GOOD
def test_create_user_success():
user = service.create_user(valid_data)
assert user.id is not None
def test_create_user_invalid_email():
with pytest.raises(ValueError, match="Invalid email"):
service.create_user(invalid_email_data)
def test_create_user_duplicate_email():
service.create_user(valid_data)
with pytest.raises(ConflictError):
service.create_user(valid_data)
# BAD: Mocking everything
def test_user_service():
mock_repo = Mock()
mock_cache = Mock()
mock_logger = Mock()
mock_metrics = Mock()
# Test doesn't verify real behavior
Fix: Use integration tests for critical paths. Mock only external services.
Before finalizing code, verify:
except Exception: pass| Anti-Pattern | Fix |
|---|---|
| Scattered retry logic | Centralized decorators |
| Hard-coded config | Environment variables + pydantic-settings |
| Exposed ORM models | DTO/response schemas |
| Mixed I/O + logic | Repository pattern |
| Bare except | Catch specific exceptions |
| Batch stops on error | Return BatchResult with successes/failures |
| No validation | Validate at boundaries with Pydantic |
| Unclosed resources | Context managers |
| Blocking in async | Async-native libraries |
| Missing types | Type annotations on all public APIs |
| Only happy path tests | Test errors and edge cases |
Weekly Installs
3.3K
Repository
GitHub Stars
32.2K
First Seen
Jan 30, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode2.7K
gemini-cli2.7K
codex2.7K
claude-code2.4K
github-copilot2.4K
cursor2.4K
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
102,200 周安装