Skip to content

Instantly share code, notes, and snippets.

@malelew
Created February 2, 2026 05:32
Show Gist options
  • Select an option

  • Save malelew/81a2f98a1bc088a9b39e108f3aca01d9 to your computer and use it in GitHub Desktop.

Select an option

Save malelew/81a2f98a1bc088a9b39e108f3aca01d9 to your computer and use it in GitHub Desktop.
name zen-of-python-refactor
description Review and refactor Python code using PEP 20 (Zen of Python) principles. Use when performing code review, refactoring complex codebases, editing AI-assisted code additions, or when the user mentions code quality, readability, or Python style.

Zen of Python Refactoring

Apply PEP 20 principles to review and refactor Python code. Run import this in Python to see the full Zen.

When to Use

  • Code review: Evaluate PRs and changes against Zen principles
  • Refactoring: Simplify complex or tangled code
  • AI-assisted edits: Review and improve large AI-generated additions (often verbose, over-nested, or implicit)

Core Principles (Prioritized for Refactoring)

1. Explicit is better than implicit

  • Avoid magic values; use named constants
  • Prefer explicit parameters over hidden defaults
  • Make side effects obvious (e.g., send_immediately=False vs. always sending)
  • AI code smell: Implicit type coercion, *args/**kwargs overuse, unclear return types

2. Readability counts

  • Names should reveal intent: user_is_authenticated over auth
  • Extract complex expressions into well-named variables
  • One logical operation per line when it aids clarity
  • AI code smell: Overly terse one-liners, cryptic variable names

3. Flat is better than nested

  • Use early returns to reduce nesting (guard clauses)
  • Target max 3–4 levels of nesting; extract to functions beyond that
  • Cyclomatic complexity > 15 suggests refactoring
  • AI code smell: Deep if/else pyramids, nested comprehensions

4. Simple is better than complex

  • Prefer sum(numbers) over reduce(lambda x, y: x + y, numbers, 0)
  • Use built-ins and stdlib before custom logic
  • AI code smell: Premature patterns, unnecessary abstractions, over-engineering

5. Sparse is better than dense

  • Use whitespace to separate logical blocks
  • One statement per line; avoid cramming logic
  • AI code smell: Dense blocks with minimal line breaks

6. Errors should never pass silently. Unless explicitly silenced.

  • Avoid bare except:; catch specific exceptions
  • Re-raise or log with context; never swallow silently
  • When silencing: add comment explaining why
  • AI code smell: Broad except Exception: pass, returning None on error without logging

7. In the face of ambiguity, refuse the temptation to guess

  • Raise ValueError with clear message when inputs are ambiguous
  • Don't infer intent from format (e.g., if '@' in x to guess email)
  • AI code smell: Implicit fallbacks, guessing from string patterns

8. If the implementation is hard to explain, it's a bad idea

  • If you can't describe it in one sentence, simplify
  • "Pain Driven Development": introduce patterns when you feel the pain, not preemptively
  • AI code smell: Clever one-liners, nested comprehensions that need a diagram to understand

9. There should be one—and preferably only one—obvious way to do it

  • Prefer enumerate() over range(len()) for indexed iteration
  • Use idiomatic Python (list comprehensions, pathlib, context managers)
  • AI code smell: Non-idiomatic patterns from other languages

10. Special cases aren't special enough to break the rules

  • Keep interfaces consistent across similar types
  • Don't rename methods for "special" cases (read_file vs read)

11. Complex is better than complicated

  • Complex: many parts, clear responsibilities
  • Complicated: tangled, mixed concerns
  • Extract mixed logic into focused functions/classes

12. Beautiful is better than ugly

  • Prefer list comprehensions over manual loops when readable
  • Use with for resource management
  • Format consistently (let formatters help)

Code Review Checklist

When reviewing, flag violations and suggest fixes:

- [ ] Intent is explicit (no guessing required)
- [ ] Nesting ≤ 3–4 levels; early returns used
- [ ] Errors handled explicitly (no silent swallow)
- [ ] Names reveal intent
- [ ] One obvious way used (idiomatic Python)
- [ ] No premature complexity (patterns only where needed)
- [ ] Implementation is explainable in one sentence

Refactoring Workflow

  1. Identify: Which Zen principle(s) are violated?
  2. Prioritize: Start with explicit/readable/flat—highest impact
  3. Refactor incrementally: One principle at a time; run tests after each change
  4. Verify: Can you explain the result in plain language?

AI-Generated Code: Common Issues

Issue Zen Principle Fix
Deep nesting Flat is better than nested Extract functions, use early returns
Verbose boilerplate Simple is better than complex Use comprehensions, built-ins
Bare except: pass Errors should never pass silently Catch specific exceptions, log or re-raise
Magic numbers/strings Explicit is better than implicit Named constants, type hints
Over-abstraction Simple is better than complex Remove unnecessary layers
Dense blocks Sparse is better than dense Add whitespace, split lines
Non-idiomatic patterns One obvious way Replace with Python idioms

Quick Examples

Nested → Flat (early returns):

# Before
def process_user(user):
    if user:
        if user.is_active:
            if user.has_permission('read'):
                return user.get_data()
    return None

# After
def process_user(user):
    if not user or not user.is_active or not user.has_permission('read'):
        return None
    return user.get_data()

Implicit → Explicit:

# Before
def send_email(recipient, subject, body):
    email = Email(recipient, subject, body)
    email.send()  # Always sends—not obvious

# After
def send_email(recipient, subject, body, send_immediately=False):
    email = Email(recipient, subject, body)
    if send_immediately:
        email.send()
    else:
        email.queue()

Silent failure → Explicit error:

# Before
def divide(a, b):
    try:
        return a / b
    except ZeroDivisionError:
        return None  # Caller doesn't know what happened

# After
def divide(a, b):
    if b == 0:
        raise ValueError(f"Cannot divide {a} by zero")
    return a / b

Feedback Format

When providing review feedback, tag by severity:

  • Critical: Violates explicit/errors/readability—must fix
  • Suggestion: Improves maintainability—consider fixing
  • Nice to have: Minor style—optional

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment