Python Anti Patterns

作者 wshobson46891e7e60da無授權條款收錄於 2026年10月8日更新於 2026年10月8日

Use this skill when reviewing Python code for common anti-patterns to avoid. Use as a checklist when reviewing code, before finalizing implementations, or when debugging issues that might stem from known bad practices.

AI 產生的概覽

用於在定案實作前審查 Python 程式碼常見反模式的檢查清單。

功能
提供一份 Python 常見錯誤與反模式的參考清單,涵蓋基礎架構、架構、錯誤處理、資源、型別安全與測試等類別。每個項目會給出錯誤範例、建議修正方式以及簡短說明。文末附有快速審查清單與反模式對應修正的對照表。
適用情境
適用於合併前審查 Python 程式碼、定案實作之前,或除錯可能源自已知不良作法的問題。也適合制定團隊編碼規範、重構舊程式碼以及教學 Python 最佳實務。
執行需求
不需要指令碼或工具,僅為純說明的參考文件。範例程式碼提到 requests、pydantic-settings、httpx、pytest 等套件,但閱讀清單本身不需要安裝它們。

Python Anti-Patterns Checklist

A reference checklist of common mistakes and anti-patterns in Python code. Review this before finalizing implementations to catch issues early.

When to Use This Skill

  • Reviewing code before merge
  • Debugging mysterious issues
  • Teaching or learning Python best practices
  • Establishing team coding standards
  • Refactoring legacy code

Note: This skill focuses on what to avoid. For guidance on positive patterns and architecture, see the python-design-patterns skill.

Infrastructure Anti-Patterns

Scattered Timeout/Retry Logic

python
# BAD: Timeout logic duplicated everywheredef 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.

python
# 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)

Double Retry

python
# BAD: Retrying at multiple layers@retry(max_attempts=3)  # Application retrydef call_service():    return client.request()  # Client also has retry configured!

Fix: Retry at one layer only. Know your infrastructure's retry behavior.

Hard-Coded Configuration

python
# BAD: Secrets and config in codeDB_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.

python
# GOODfrom pydantic_settings import BaseSettings
class Settings(BaseSettings):    db_host: str = Field(alias="DB_HOST")    api_key: str = Field(alias="API_KEY")
settings = Settings()

Architecture Anti-Patterns

Exposed Internal Types

python
# 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.

python
# GOOD@app.get("/users/{id}")def get_user(id: str) -> UserResponse:    user = db.query(UserModel).get(id)    return UserResponse.from_orm(user)

Mixed I/O and Business Logic

python
# BAD: SQL embedded in business logicdef 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.

python
# GOODdef calculate_discount(user: User, orders: list[Order]) -> float:    # Pure business logic, easily testable    if len(orders) > 10:        return 0.15    return 0.0

Error Handling Anti-Patterns

Bare Exception Handling

python
# BAD: Swallowing all exceptionstry:    process()except Exception:    pass  # Silent failure - bugs hidden forever

Fix: Catch specific exceptions. Log or handle appropriately.

python
# GOODtry:    process()except ConnectionError as e:    logger.warning("Connection failed, will retry", error=str(e))    raiseexcept ValueError as e:    logger.error("Invalid input", error=str(e))    raise BadRequestError(str(e))

Ignored Partial Failures

python
# BAD: Stops on first errordef 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.

python
# GOODdef 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)

Missing Input Validation

python
# BAD: No validationdef create_user(data: dict):    return User(**data)  # Crashes deep in code on bad input

Fix: Validate early at API boundaries.

python
# GOODdef create_user(data: dict) -> User:    validated = CreateUserInput.model_validate(data)    return User.from_input(validated)

Resource Anti-Patterns

Unclosed Resources

python
# BAD: File never closeddef read_file(path):    f = open(path)    return f.read()  # What if this raises?

Fix: Use context managers.

python
# GOODdef read_file(path):    with open(path) as f:        return f.read()

Blocking in Async

python
# BAD: Blocks the entire event loopasync def fetch_data():    time.sleep(1)  # Blocks everything!    response = requests.get(url)  # Also blocks!

Fix: Use async-native libraries.

python
# GOODasync def fetch_data():    await asyncio.sleep(1)    async with httpx.AsyncClient() as client:        response = await client.get(url)

Type Safety Anti-Patterns

Missing Type Hints

python
# BAD: No typesdef process(data):    return data["value"] * 2

Fix: Annotate all public functions.

python
# GOODdef process(data: dict[str, int]) -> int:    return data["value"] * 2

Untyped Collections

python
# BAD: Generic list without type parameterdef get_users() -> list:    ...

Fix: Use type parameters.

python
# GOODdef get_users() -> list[User]:    ...

Testing Anti-Patterns

Only Testing Happy Paths

python
# BAD: Only tests success casedef test_create_user():    user = service.create_user(valid_data)    assert user.id is not None

Fix: Test error conditions and edge cases.

python
# GOODdef 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)

Over-Mocking

python
# BAD: Mocking everythingdef 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.

Quick Review Checklist

Before finalizing code, verify:

  • No scattered timeout/retry logic (centralized)
  • No double retry (app + infrastructure)
  • No hard-coded configuration or secrets
  • No exposed internal types (ORM models, protobufs)
  • No mixed I/O and business logic
  • No bare except Exception: pass
  • No ignored partial failures in batches
  • No missing input validation
  • No unclosed resources (using context managers)
  • No blocking calls in async code
  • All public functions have type hints
  • Collections have type parameters
  • Error paths are tested
  • Edge cases are covered

Common Fixes Summary

Anti-PatternFix
Scattered retry logicCentralized decorators
Hard-coded configEnvironment variables + pydantic-settings
Exposed ORM modelsDTO/response schemas
Mixed I/O + logicRepository pattern
Bare exceptCatch specific exceptions
Batch stops on errorReturn BatchResult with successes/failures
No validationValidate at boundaries with Pydantic
Unclosed resourcesContext managers
Blocking in asyncAsync-native libraries
Missing typesType annotations on all public APIs
Only happy path testsTest errors and edge cases

來源與署名

來源:wshobson/agents位於plugins/python-development/skills/python-anti-patterns提交46891e7

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架