Python Code Simplifier
Transform complex, hard-to-maintain Python code into clean, readable, idiomatic solutions.
Analysis Scripts
Comprehensive analysis (runs all checks)
python scripts/analyze_all.py /path/to/project
Individual analyzers:
python scripts/analyze_complexity.py . # Cyclomatic/cognitive complexity python scripts/find_code_smells.py . # Mutable defaults, bare excepts, etc. python scripts/find_overengineering.py . # YAGNI violations, unused abstractions python scripts/find_dead_code.py . # Unused imports, functions, variables python scripts/find_unpythonic.py . # Non-idiomatic patterns python scripts/find_coupling_issues.py . # Feature envy, low cohesion python scripts/find_duplicates.py . # Structural duplicate detection
JSON output for CI/tooling
python scripts/analyze_all.py . --format json > report.json
Workflow
-
Analyze: Run analyze_all.py to identify all issues
-
Prioritize: Address high-severity issues (🔴) first
-
Simplify: Apply patterns below incrementally
-
Verify: Ensure simplified code is functionally equivalent
Simplification Principles
-
YAGNI: Don't add abstractions until needed
-
Preserve behavior: Simplification ≠ changing functionality
-
One change at a time: Incremental is safer
-
Readability over cleverness: Clear beats "smart"
-
Keep related code together: Locality matters
Common Simplification Patterns
Extract and Name
Before: Complex inline condition
if user.age >= 18 and user.country in ALLOWED and not user.banned:
After: Named condition
is_eligible = user.age >= 18 and user.country in ALLOWED and not user.banned if is_eligible:
Early Returns
Before: Deep nesting
def process(data): if data: if data.valid: if data.ready: return compute(data) return None
After: Guard clauses
def process(data): if not data or not data.valid or not data.ready: return None return compute(data)
Comprehensions
Before: Manual loop
result = [] for item in items: if item.active: result.append(item.name)
After: List comprehension
result = [item.name for item in items if item.active]
Dictionary Techniques
Before: Verbose key checking
if key in d: value = d[key] else: value = default
After: get() with default
value = d.get(key, default)
Before: Manual grouping
groups = {} for item in items: if item.category not in groups: groups[item.category] = [] groups[item.category].append(item)
After: defaultdict
from collections import defaultdict groups = defaultdict(list) for item in items: groups[item.category].append(item)
Context Managers
Before: Manual cleanup
f = open('file.txt') try: data = f.read() finally: f.close()
After: with statement
with open('file.txt') as f: data = f.read()
Over-Engineering Anti-Patterns
Pattern Problem Solution
Single-impl interface Abstract class with one subclass Merge or wait for need
Unnecessary factory Factory that creates one type Direct instantiation
Premature strategy Strategy pattern with one strategy Simple function
Thin wrapper Class that just delegates Use wrapped class directly
Speculative generality Code for "future needs" Delete it (YAGNI)
Deep inheritance 4+ levels of inheritance Composition over inheritance
Code Smells Quick Reference
Smell Detection Fix
Mutable default def f(x=[])
Use None , create inside
Bare except except:
except Exception:
God class 15+ methods, 10+ attrs Split into focused classes
Long function 50+ lines Extract helper functions
Deep nesting 4+ levels Early returns, extract
Feature envy Method uses other class more Move method
Magic numbers Unexplained numeric literals Named constants
Script Reference
Script What It Detects
analyze_complexity.py
Cyclomatic complexity, cognitive complexity, nesting depth, function length, parameter count, class size
find_code_smells.py
Mutable defaults, bare excepts, magic numbers, type comparisons, god classes, data classes, boolean blindness
find_overengineering.py
Single-implementation interfaces, unused abstractions, unnecessary factories/builders, thin wrappers, premature strategies
find_dead_code.py
Unused imports, unused functions/classes, unused parameters, unreachable code, constant conditions
find_unpythonic.py
range(len()) , == True/False/None , swallowed exceptions, manual index tracking
find_coupling_issues.py
Feature envy, low cohesion (LCOM), message chains, middle man classes
find_duplicates.py
Structurally similar code blocks using AST normalization
When NOT to Simplify
-
Working legacy code with no tests
-
Performance-critical hot paths (measure first)
-
Code that will be replaced soon
-
External API constraints requiring complexity