Python反模式检查清单Skill python-anti-patterns

这个技能提供了一个Python代码反模式的检查清单,帮助开发者在代码审查、调试、教学等场景中避免常见错误,提升代码质量。关键词:Python、反模式、代码审查、调试、最佳实践、软件测试、代码质量、开发效率。

测试 0 次安装 0 次浏览 更新于 3/22/2026

name: python-anti-patterns description: 避免的常见Python反模式。在审查代码、最终确定实现或调试可能源于已知不良实践的问题时用作检查清单。

Python反模式检查清单

一个Python代码中常见错误和反模式的参考检查清单。在最终确定实现前审查此清单,以早期发现问题。

何时使用此技能

  • 合并前审查代码
  • 调试神秘问题
  • 教学或学习Python最佳实践
  • 建立团队编码标准
  • 重构遗留代码

注意: 此技能侧重于避免什么。关于积极模式和架构的指导,请参见python-design-patterns技能。

基础设施反模式

分散的超时/重试逻辑

# 坏:超时逻辑到处重复
def fetch_user(user_id):
    try:
        return requests.get(url, timeout=30)
    except Timeout:
        logger.warning("获取用户超时")
        return None

def fetch_orders(user_id):
    try:
        return requests.get(url, timeout=30)
    except Timeout:
        logger.warning("获取订单超时")
        return None

修复: 集中在装饰器或客户端包装器中。

# 好:集中重试逻辑
@retry(stop=stop_after_attempt(3), wait=wait_exponential())
def http_get(url: str) -> Response:
    return requests.get(url, timeout=30)

双重重试

# 坏:在多个层重试
@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)

混合I/O和业务逻辑

# 坏: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("连接失败,将重试", error=str(e))
    raise
except ValueError as e:
    logger.error("无效输入", 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()
    # 测试不验证真实行为

修复: 对关键路径使用集成测试。只模拟外部服务。

快速审查检查清单

在最终确定代码前,验证:

  • [ ] 无分散的超时/重试逻辑(集中化)
  • [ ] 无双重重试(应用+基础设施)
  • [ ] 无硬编码配置或秘密
  • [ ] 无暴露内部类型(ORM模型、protobufs)
  • [ ] 无混合I/O和业务逻辑
  • [ ] 无裸except Exception: pass
  • [ ] 无忽略批次中的部分失败
  • [ ] 无缺少输入验证
  • [ ] 无未关闭资源(使用上下文管理器)
  • [ ] 无异步中的阻塞调用
  • [ ] 所有公共函数都有类型提示
  • [ ] 集合有类型参数
  • [ ] 错误路径经过测试
  • [ ] 边缘情况覆盖

常见修复摘要

反模式 修复
分散重试逻辑 集中装饰器
硬编码配置 环境变量 + pydantic-settings
暴露ORM模型 DTO/响应模式
混合I/O + 逻辑 仓储模式
裸异常 捕获特定异常
批次因错误停止 返回BatchResult包含成功/失败
无验证 使用Pydantic在边界验证
未关闭资源 上下文管理器
异步中阻塞 异步原生库
缺少类型 所有公共API的类型注释
只快乐路径测试 测试错误和边缘情况