| 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. |
Apply PEP 20 principles to review and refactor Python code. Run import this in Python to see the full Zen.
- 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)
- Avoid magic values; use named constants
- Prefer explicit parameters over hidden defaults
- Make side effects obvious (e.g.,
send_immediately=Falsevs. always sending) - AI code smell: Implicit type coercion,
*args/**kwargsoveruse, unclear return types
- Names should reveal intent:
user_is_authenticatedoverauth - 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
- 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
- Prefer
sum(numbers)overreduce(lambda x, y: x + y, numbers, 0) - Use built-ins and stdlib before custom logic
- AI code smell: Premature patterns, unnecessary abstractions, over-engineering
- Use whitespace to separate logical blocks
- One statement per line; avoid cramming logic
- AI code smell: Dense blocks with minimal line breaks
- 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, returningNoneon error without logging
- Raise
ValueErrorwith clear message when inputs are ambiguous - Don't infer intent from format (e.g.,
if '@' in xto guess email) - AI code smell: Implicit fallbacks, guessing from string patterns
- 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
- Prefer
enumerate()overrange(len())for indexed iteration - Use idiomatic Python (list comprehensions,
pathlib, context managers) - AI code smell: Non-idiomatic patterns from other languages
- Keep interfaces consistent across similar types
- Don't rename methods for "special" cases (
read_filevsread)
- Complex: many parts, clear responsibilities
- Complicated: tangled, mixed concerns
- Extract mixed logic into focused functions/classes
- Prefer list comprehensions over manual loops when readable
- Use
withfor resource management - Format consistently (let formatters help)
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
- Identify: Which Zen principle(s) are violated?
- Prioritize: Start with explicit/readable/flat—highest impact
- Refactor incrementally: One principle at a time; run tests after each change
- Verify: Can you explain the result in plain language?
| 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 |
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 / bWhen providing review feedback, tag by severity:
- Critical: Violates explicit/errors/readability—must fix
- Suggestion: Improves maintainability—consider fixing
- Nice to have: Minor style—optional
- PEP 20 — The Zen of Python
- PEP 8 — Style guide (complements Zen)
- PEP 20: The Zen of Python - Design Philosophy and Guiding Principles