python-patterns
Guides idiomatic Python design and resource handling. Use when refactoring Python modules, adding type hints, or choosing a concurrency model.
SKILL.mdycc/skills/python-patterns/SKILL.md
GitHubPython Development Patterns
Idiomatic Python patterns and best practices for building robust, efficient, and maintainable applications.
When to Activate
- Writing new Python code
- Reviewing Python code
- Refactoring existing Python code
- Designing Python packages/modules
Critical Rules
- Prefer EAFP (try/except) over LBYL checks.
- Annotate function signatures with type hints.
- Catch specific exceptions, never bare
except; chain withraise ... from e. - Use
withfor resource management. - No mutable default arguments; compare to
Nonewithis None. - No
from module import *. - Choose the concurrency model by workload:
asyncio, threads for I/O, processes for CPU.
References
Paths are relative to this SKILL.md's directory. Read only the file that matches the task. If a file cannot be read, say so.
references/core-idioms.md Read when: Core Principles (readability, explicit, EAFP), Type Hints, Error Handling Patterns, Context Managers, Comprehensions and Generators.
references/design-and-tooling.md Read when: Data Classes and Named Tuples, Decorators, Concurrency Patterns (threads, processes, asyncio), Package Organization, Memory and Performance, Python Tooling Integration.
Quick Reference: Python Idioms
| Idiom | Description |
|---|---|
| EAFP | Easier to Ask Forgiveness than Permission |
| Context managers | Use with for resource management |
| List comprehensions | For simple transformations |
| Generators | For lazy evaluation and large datasets |
| Type hints | Annotate function signatures |
| Dataclasses | For data containers with auto-generated methods |
__slots__ |
For memory optimization |
| f-strings | For string formatting (Python 3.6+) |
pathlib.Path |
For path operations (Python 3.4+) |
enumerate |
For index-element pairs in loops |
Anti-Patterns to Avoid
# Bad: Mutable default arguments
def append_to(item, items=[]):
items.append(item)
return items
# Good: Use None and create new list
def append_to(item, items=None):
if items is None:
items = []
items.append(item)
return items
# Bad: Checking type with type()
if type(obj) == list:
process(obj)
# Good: Use isinstance
if isinstance(obj, list):
process(obj)
# Bad: Comparing to None with ==
if value == None:
process()
# Good: Use is
if value is None:
process()
# Bad: from module import *
from os.path import *
# Good: Explicit imports
from os.path import join, exists
# Bad: Bare except
try:
risky_operation()
except:
pass
# Good: Specific exception
try:
risky_operation()
except SpecificError as e:
logger.error(f"Operation failed: {e}")
Remember: Python code should be readable, explicit, and follow the principle of least surprise. When in doubt, prioritize clarity over cleverness.