Effective Python Skill
Apply the 90 items from Brett Slatkin's "Effective Python" (2nd Edition) to review existing code and write new Python code. This skill operates in two modes: Review Mode (analyze code for violations) and Write Mode (produce idiomatic Python from scratch).
Reference Files
This skill includes categorized reference files with all 90 items:
ref-01-pythonic-thinking.md — Items 1-10: PEP 8, f-strings, bytes/str, walrus operator, unpacking, enumerate, zip, slicing
ref-02-lists-and-dicts.md — Items 11-18: Slicing, sorting, dict ordering, defaultdict, missing
ref-03-functions.md — Items 19-26: Exceptions vs None, closures, *args/**kwargs, keyword-only args, decorators
ref-04-comprehensions-generators.md — Items 27-36: Comprehensions, generators, yield from, itertools
ref-05-classes-interfaces.md — Items 37-43: Composition, @classmethod, super(), mix-ins, public attrs
ref-06-metaclasses-attributes.md — Items 44-51: @property, descriptors, getattr, init_subclass, class decorators
ref-07-concurrency.md — Items 52-64: subprocess, threads, Lock, Queue, coroutines, asyncio
ref-08-robustness-performance.md — Items 65-76: try/except, contextlib, datetime, decimal, profiling, data structures
ref-09-testing-debugging.md — Items 77-85: TestCase, mocks, dependency injection, pdb, tracemalloc
ref-10-collaboration.md — Items 86-90: Docstrings, packages, root exceptions, virtual environments
How to Use This Skill
Before responding, read the relevant reference files based on the code's topic. For a general review, read all files. For targeted work (e.g., writing async code), read the specific reference (e.g., ref-07-concurrency.md).
Mode 1: Code Review
When the user asks you to review existing Python code, follow this process:
Step 1: Read Relevant References
Determine which chapters apply to the code under review and read those reference files. If unsure, read all of them.
Step 2: Analyze the Code
For each relevant item from the book, check whether the code follows or violates the guideline. Focus on:
- Style and Idiom (Items 1-10): Is it Pythonic? Does it use f-strings, unpacking, enumerate, zip properly?
- Data Structures (Items 11-18): Are lists and dicts used correctly? Is sorting done with key functions?
- Function Design (Items 19-26): Do functions raise exceptions instead of returning None? Are args well-structured?
- Comprehensions & Generators (Items 27-36): Are comprehensions preferred over map/filter? Are generators used for large sequences?
- Class Design (Items 37-43): Is composition preferred over deep nesting? Are mix-ins used correctly?
- Metaclasses & Attributes (Items 44-51): Are plain attributes used instead of getter/setter methods? Is @property used appropriately?
- Concurrency (Items 52-64): Are threads used only for I/O? Is asyncio structured correctly?
- Robustness (Items 65-76): Is error handling structured with try/except/else/finally? Are the right data structures chosen?
- Testing (Items 77-85): Are tests well-structured? Are mocks used appropriately?
- Collaboration (Items 86-90): Are docstrings present? Are APIs stable?
Step 3: Report Findings
For each issue found, report:
- Item number and name (e.g., "Item 4: Prefer Interpolated F-Strings")
- Location in the code
- What's wrong (the anti-pattern)
- How to fix it (the Pythonic way)
- Priority: Critical (bugs/correctness), Important (maintainability), Suggestion (style)
Step 4: Provide Fixed Code
Offer a corrected version of the code with all issues addressed, with comments explaining each change.
Mode 2: Writing New Code
When the user asks you to write new Python code, follow these principles:
Always Apply These Core Practices
Follow PEP 8 — Use consistent naming (snake_case for functions/variables, PascalCase for classes). Use pylint and black-compatible style.
Use f-strings for string formatting (Item 4). Never use % or .format() for simple cases.
Use unpacking instead of indexing (Item 6). Prefer first, second = my_list over my_list[0].
Use enumerate instead of range(len(...)) (Item 7).
Use zip to iterate over multiple lists in parallel (Item 8). Use zip_longest from itertools when lengths differ.
Avoid else blocks after for/while loops (Item 9).
Use assignment expressions (:= walrus operator) to reduce repetition when appropriate (Item 10).
Raise exceptions instead of returning None for failure cases (Item 20).
Use keyword-only arguments for clarity (Item 25). Use positional-only args to separate API from implementation (Item 25).
Use functools.wraps on all decorators (Item 26).
Prefer comprehensions over map/filter (Item 27). Keep them simple — no more than two expressions (Item 28).
Use generators for large sequences instead of returning lists (Item 30).
Prefer composition over deeply nested classes (Item 37).
Use @classmethod for polymorphic constructors (Item 39).
Always call super().init (Item 40).
Use plain attributes instead of getter/setter methods. Use @property for special behavior (Item 44).
Use try/except/else/finally structure correctly (Item 65).
Write docstrings for every module, class, and function (Item 84).
Code Structure Template
When writing new modules or classes, follow this structure:
"""Module docstring describing purpose."""
# Standard library imports
# Third-party imports
# Local imports
# Module-level constants
class MyClass:
"""Class docstring describing purpose and usage.
Attributes:
attr_name: Description of attribute.
"""
def __init__(self, param: type) -> None:
"""Initialize with description of params."""
self.param = param # Use public attributes (Item 42)
@classmethod
def from_alternative(cls, data):
"""Alternative constructor (Item 39)."""
return cls(processed_data)
def method(self, arg: type) -> return_type:
"""Method docstring.
Args:
arg: Description.
Returns:
Description of return value.
Raises:
ValueError: When arg is invalid (Item 20).
"""
pass
Concurrency Guidelines
- Use
subprocess for managing child processes (Item 52)
- Use threads only for blocking I/O, never for parallelism (Item 53)
- Use
threading.Lock to prevent data races (Item 54)
- Use
Queue for coordinating work between threads (Item 55)
- Use
asyncio for highly concurrent I/O (Item 60)
- Never mix blocking calls in async code (Item 62)
Testing Guidelines
- Subclass
TestCase and use setUp/tearDown (Item 78)
- Use
unittest.mock for complex dependencies (Item 78)
- Encapsulate dependencies to make code testable (Item 79)
- Use
pdb.set_trace() or breakpoint() for debugging (Item 80)
- Use
tracemalloc for memory debugging (Item 81)
Priority of Items by Impact
When time is limited, focus on these highest-impact items first:
Critical (Correctness & Bugs)
- Item 20: Raise exceptions instead of returning None
- Item 53: Use threads for I/O only, not parallelism
- Item 54: Use Lock to prevent data races
- Item 40: Initialize parent classes with super()
- Item 65: Use try/except/else/finally correctly
- Item 73: Use datetime instead of time module for timezone handling
Important (Maintainability)
- Item 1: Follow PEP 8 style
- Item 4: Use f-strings
- Item 19: Never unpack more than 3 variables
- Item 25: Use keyword-only and positional-only arguments
- Item 26: Use functools.wraps for decorators
- Item 37: Compose classes instead of deep nesting
- Item 42: Prefer public attributes over private
- Item 44: Use plain attributes over getter/setter
- Item 84: Write docstrings for all public APIs
Suggestions (Polish & Optimization)
- Item 7: Use enumerate instead of range
- Item 8: Use zip for parallel iteration
- Item 10: Use walrus operator to reduce repetition
- Item 27: Use comprehensions over map/filter
- Item 30: Use generators for large sequences
- Item 70: Profile before optimizing (cProfile)
1---2name: effective-python3description: Review existing Python code and write new Python code following the 90 best practices from "Effective Python" by Brett Slatkin (2nd Edition). Use when writing Python, reviewing Python code, or wanting idiomatic, Pythonic solutions.4---5
6# Effective Python Skill
7
8Apply the 90 items from Brett Slatkin's "Effective Python" (2nd Edition) to review existing code and write new Python code. This skill operates in two modes: **Review Mode** (analyze code for violations) and **Write Mode** (produce idiomatic Python from scratch).
9
10## Reference Files
11
12This skill includes categorized reference files with all 90 items:
13
14- `ref-01-pythonic-thinking.md` — Items 1-10: PEP 8, f-strings, bytes/str, walrus operator, unpacking, enumerate, zip, slicing
15- `ref-02-lists-and-dicts.md` — Items 11-18: Slicing, sorting, dict ordering, defaultdict, __missing__
16- `ref-03-functions.md` — Items 19-26: Exceptions vs None, closures, *args/**kwargs, keyword-only args, decorators
17- `ref-04-comprehensions-generators.md` — Items 27-36: Comprehensions, generators, yield from, itertools
18- `ref-05-classes-interfaces.md` — Items 37-43: Composition, @classmethod, super(), mix-ins, public attrs
19- `ref-06-metaclasses-attributes.md` — Items 44-51: @property, descriptors, __getattr__, __init_subclass__, class decorators
20- `ref-07-concurrency.md` — Items 52-64: subprocess, threads, Lock, Queue, coroutines, asyncio
21- `ref-08-robustness-performance.md` — Items 65-76: try/except, contextlib, datetime, decimal, profiling, data structures
22- `ref-09-testing-debugging.md` — Items 77-85: TestCase, mocks, dependency injection, pdb, tracemalloc
23- `ref-10-collaboration.md` — Items 86-90: Docstrings, packages, root exceptions, virtual environments
24
25## How to Use This Skill
26
27**Before responding**, read the relevant reference files based on the code's topic. For a general review, read all files. For targeted work (e.g., writing async code), read the specific reference (e.g., `ref-07-concurrency.md`).
28
29---
30
31## Mode 1: Code Review
32
33When the user asks you to **review** existing Python code, follow this process:
34
35### Step 1: Read Relevant References
36Determine which chapters apply to the code under review and read those reference files. If unsure, read all of them.
37
38### Step 2: Analyze the Code
39For each relevant item from the book, check whether the code follows or violates the guideline. Focus on:
40
411. **Style and Idiom** (Items 1-10): Is it Pythonic? Does it use f-strings, unpacking, enumerate, zip properly?
422. **Data Structures** (Items 11-18): Are lists and dicts used correctly? Is sorting done with key functions?
433. **Function Design** (Items 19-26): Do functions raise exceptions instead of returning None? Are args well-structured?
444. **Comprehensions & Generators** (Items 27-36): Are comprehensions preferred over map/filter? Are generators used for large sequences?
455. **Class Design** (Items 37-43): Is composition preferred over deep nesting? Are mix-ins used correctly?
466. **Metaclasses & Attributes** (Items 44-51): Are plain attributes used instead of getter/setter methods? Is @property used appropriately?
477. **Concurrency** (Items 52-64): Are threads used only for I/O? Is asyncio structured correctly?
488. **Robustness** (Items 65-76): Is error handling structured with try/except/else/finally? Are the right data structures chosen?
499. **Testing** (Items 77-85): Are tests well-structured? Are mocks used appropriately?
5010. **Collaboration** (Items 86-90): Are docstrings present? Are APIs stable?
51
52### Step 3: Report Findings
53For each issue found, report:
54- **Item number and name** (e.g., "Item 4: Prefer Interpolated F-Strings")
55- **Location** in the code
56- **What's wrong** (the anti-pattern)
57- **How to fix it** (the Pythonic way)
58- **Priority**: Critical (bugs/correctness), Important (maintainability), Suggestion (style)
59
60### Step 4: Provide Fixed Code
61Offer a corrected version of the code with all issues addressed, with comments explaining each change.
62
63---
64
65## Mode 2: Writing New Code
66
67When the user asks you to **write** new Python code, follow these principles:
68
69### Always Apply These Core Practices
70
711. **Follow PEP 8** — Use consistent naming (snake_case for functions/variables, PascalCase for classes). Use `pylint` and `black`-compatible style.
72
732. **Use f-strings** for string formatting (Item 4). Never use % or .format() for simple cases.
74
753. **Use unpacking** instead of indexing (Item 6). Prefer `first, second = my_list` over `my_list[0]`.
76
774. **Use enumerate** instead of range(len(...)) (Item 7).
78
795. **Use zip** to iterate over multiple lists in parallel (Item 8). Use `zip_longest` from itertools when lengths differ.
80
816. **Avoid else blocks** after for/while loops (Item 9).
82
837. **Use assignment expressions** (:= walrus operator) to reduce repetition when appropriate (Item 10).
84
858. **Raise exceptions** instead of returning None for failure cases (Item 20).
86
879. **Use keyword-only arguments** for clarity (Item 25). Use positional-only args to separate API from implementation (Item 25).
88
8910. **Use functools.wraps** on all decorators (Item 26).
90
9111. **Prefer comprehensions** over map/filter (Item 27). Keep them simple — no more than two expressions (Item 28).
92
9312. **Use generators** for large sequences instead of returning lists (Item 30).
94
9513. **Prefer composition** over deeply nested classes (Item 37).
96
9714. **Use @classmethod** for polymorphic constructors (Item 39).
98
9915. **Always call super().__init__** (Item 40).
100
10116. **Use plain attributes** instead of getter/setter methods. Use @property for special behavior (Item 44).
102
10317. **Use try/except/else/finally** structure correctly (Item 65).
104
10518. **Write docstrings** for every module, class, and function (Item 84).
106
107### Code Structure Template
108
109When writing new modules or classes, follow this structure:
110
111```python
112"""Module docstring describing purpose."""
113
114# Standard library imports
115# Third-party imports
116# Local imports
117
118# Module-level constants
119
120class MyClass:
121 """Class docstring describing purpose and usage.
122
123 Attributes:
124 attr_name: Description of attribute.
125 """
126
127 def __init__(self, param: type) -> None:
128 """Initialize with description of params."""
129 self.param = param # Use public attributes (Item 42)
130
131 @classmethod
132 def from_alternative(cls, data):
133 """Alternative constructor (Item 39)."""
134 return cls(processed_data)
135
136 def method(self, arg: type) -> return_type:
137 """Method docstring.
138
139 Args:
140 arg: Description.
141
142 Returns:
143 Description of return value.
144
145 Raises:
146 ValueError: When arg is invalid (Item 20).
147 """
148 pass
149```
150
151### Concurrency Guidelines
152
153- Use `subprocess` for managing child processes (Item 52)
154- Use threads **only** for blocking I/O, never for parallelism (Item 53)
155- Use `threading.Lock` to prevent data races (Item 54)
156- Use `Queue` for coordinating work between threads (Item 55)
157- Use `asyncio` for highly concurrent I/O (Item 60)
158- Never mix blocking calls in async code (Item 62)
159
160### Testing Guidelines
161
162- Subclass `TestCase` and use `setUp`/`tearDown` (Item 78)
163- Use `unittest.mock` for complex dependencies (Item 78)
164- Encapsulate dependencies to make code testable (Item 79)
165- Use `pdb.set_trace()` or `breakpoint()` for debugging (Item 80)
166- Use `tracemalloc` for memory debugging (Item 81)
167
168---
169
170## Priority of Items by Impact
171
172When time is limited, focus on these highest-impact items first:
173
174### Critical (Correctness & Bugs)
175- Item 20: Raise exceptions instead of returning None
176- Item 53: Use threads for I/O only, not parallelism
177- Item 54: Use Lock to prevent data races
178- Item 40: Initialize parent classes with super()
179- Item 65: Use try/except/else/finally correctly
180- Item 73: Use datetime instead of time module for timezone handling
181
182### Important (Maintainability)
183- Item 1: Follow PEP 8 style
184- Item 4: Use f-strings
185- Item 19: Never unpack more than 3 variables
186- Item 25: Use keyword-only and positional-only arguments
187- Item 26: Use functools.wraps for decorators
188- Item 37: Compose classes instead of deep nesting
189- Item 42: Prefer public attributes over private
190- Item 44: Use plain attributes over getter/setter
191- Item 84: Write docstrings for all public APIs
192
193### Suggestions (Polish & Optimization)
194- Item 7: Use enumerate instead of range
195- Item 8: Use zip for parallel iteration
196- Item 10: Use walrus operator to reduce repetition
197- Item 27: Use comprehensions over map/filter
198- Item 30: Use generators for large sequences
199- Item 70: Profile before optimizing (cProfile)