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: Calibrate Your Response
If the code is already well-written and idiomatic:
- Say so explicitly and upfront. Do not manufacture issues to appear thorough.
- Praise the good patterns you see (see "Praising Good Patterns" below).
- Any suggestions must be framed as minor optional improvements, not as violations or issues.
If the code has real problems:
- Identify and report them clearly with item references.
Step 3: Praise Good Patterns (when present)
When the code uses these patterns correctly, explicitly praise them:
Step 4: Analyze the Code for Issues
For each relevant item from the book, check whether the code follows or violates the guideline. Focus on:
Key Anti-Patterns to Always Check
RIGHT — use None sentinel
def process(results=None):
if results is None:
results = []
results.append(...)
- **Bare `except:`** clause (Item 65): `except:` without a type catches `KeyboardInterrupt`, `SystemExit`, and `GeneratorExit`, silently killing the program. Always catch specific exception types: `except (ValueError, KeyError):` or at minimum `except Exception:`.
- **`for i in range(len(seq))`** (Item 7): Use `for item in seq` directly, or `for i, item in enumerate(seq)` when you need the index.
- **Manual list-building loops** (Item 27): Any loop that creates an empty list and appends inside the loop body should be a list comprehension.
```python
# WRONG
result = []
for x in items:
if x > 0:
result.append(x * 2)
# RIGHT
result = [x * 2 for x in items if x > 0]
Java-style getter/setter methods (Item 44): get_name(), set_price(), get_value() are non-Pythonic. Access attributes directly or use @property when validation is required.
== True / == False comparisons (Item 2 / PEP 8): if x == True: should be if x:. return self.in_stock == True should be return self.in_stock.
Double-underscore name mangling (Item 42): self.__items makes the attribute inaccessible to subclasses and creates maintenance friction. Use single underscore self._items to signal "internal use" without enforced hiding.
Plain data-holder class without @dataclass (Items 37–43): Any class whose __init__ only assigns parameters to self.attr with no logic should be a @dataclass. Dataclasses automatically generate __repr__, __eq__, and __init__, and signal the data-holder intent. Crucially: @dataclass and @property can coexist. If one field needs validation, make it a @property with a setter inside the @dataclass. This is the correct Pythonic pattern — do NOT abandon @dataclass just because one field has a validator.
from dataclasses import dataclass, field
@dataclass
class Product:
name: str
category: str
in_stock: bool = True
_price: float = field(default=0.0, repr=False)
@property
def price(self) -> float:
return self._price
@price.setter
def price(self, value: float) -> None:
if value < 0:
raise ValueError('Price cannot be negative')
self._price = value
Missing __repr__ (Items 37–43): Any class that is not a @dataclass should define __repr__ to aid debugging. Without it, repr(obj) shows only the class name and memory address.
Returning None for failure (Item 20): Functions should raise exceptions for error conditions, not return None. Returning None forces callers to check for None every time and doesn't carry error information.
else block after for/while (Item 9): The loop-else clause fires when the loop completes without a break, which is rarely the intended semantics and confuses readers. Avoid it.
Step 5: 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 6: 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
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 None as the default for mutable default arguments (Item 24). Never use [], {}, or any other mutable object as a default argument value; initialize inside the function body.
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).
Use @dataclass for plain data-holder classes (Items 37–43). A @dataclass automatically provides __init__, __repr__, and __eq__, and makes the data-holder intent explicit. Only write a manual __init__ when you need real logic that a dataclass can't handle. Add __repr__ to any class that doesn't use @dataclass, to make debugging easier.
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). Always catch specific exception types, never bare except:.
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
# WRONG — mutable default causes shared state across all calls
def append_to(element, to=[]):
to.append(element)
return to
# RIGHT — use None sentinel, initialize inside
def append_to(element, to=None):
if to is None:
to = []
to.append(element)
return to
# WRONG — manual __init__ boilerplate for data holder
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# RIGHT — @dataclass provides __init__, __repr__, __eq__ for free
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
Important: @dataclass and @property are compatible. When one field needs validation, use both — the @dataclass handles the boilerplate and the @property handles validation. Do NOT fall back to a plain class just because one field has a setter.
# WRONG — abandoning @dataclass because price needs validation
class Product:
def __init__(self, name, price, category):
self.name = name
self.price = price # validation via set_price()
self.category = category
def set_price(self, value):
if value < 0:
raise ValueError("Price cannot be negative")
self.price = value
# RIGHT — @dataclass + @property work together
from dataclasses import dataclass, field
@dataclass
class Product:
name: str
category: str
in_stock: bool = True
_price: float = field(default=0.0, repr=False)
@property
def price(self) -> float:
return self._price
@price.setter
def price(self, value: float) -> None:
if value < 0:
raise ValueError("Price cannot be negative")
self._price = value
# WRONG — Java-style getter/setter
class Temperature:
def get_celsius(self):
return self._celsius
def set_celsius(self, value):
if value < -273.15:
raise ValueError("Temperature below absolute zero")
self._celsius = value
# RIGHT — use @property for validation, direct access otherwise
class Temperature:
def __init__(self, celsius: float) -> None:
self.celsius = celsius # triggers setter on construction
@property
def celsius(self) -> float:
return self._celsius
@celsius.setter
def celsius(self, value: float) -> None:
if value < -273.15:
raise ValueError("Temperature below absolute zero")
self._celsius = value
# WRONG — manual loop to build list
result = []
for order in orders:
if order['total'] > threshold:
result.append(order)
# RIGHT — list comprehension
result = [order for order in orders if order['total'] > threshold]
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 24: Use None as default for mutable arguments (never
[] or {})
- 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; always catch specific exception types
- 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 7: Use
for item in seq or enumerate; never range(len(seq))
- Item 19: Never unpack more than 3 variables
- Item 25: Use keyword-only and positional-only arguments
- Item 26: Use functools.wraps for decorators
- Items 37–43: Use
@dataclass for plain data holders; add __repr__ to any class without it
- Item 42: Prefer public attributes over private; use single underscore for internal
- Item 44: Use plain attributes over getter/setter; use @property for validation
- Item 66: Use
@contextmanager for reusable resource management patterns
- Item 84: Write docstrings for all public APIs
Suggestions (Polish & Optimization)
- Item 8: Use zip for parallel iteration
- Item 10: Use walrus operator to reduce repetition
- Item 27: Use comprehensions over map/filter and manual loops
- Item 30: Use generators for large sequences
- Item 70: Profile before optimizing (cProfile)
Reviewing Already-Good Code
When the submitted code is already idiomatic and well-structured, the review must:
- Lead with affirmative praise — say explicitly that the code is idiomatic / well-written.
- Call out each strong pattern by name and item, e.g.:
@contextmanager usage → praise as Item 66
- Generator functions (
yield) → praise as Item 30
- Type annotations on public functions → praise as Item 84
- Docstrings on public APIs → praise as Item 84
@dataclass for data holders → praise as Items 37–43
- List/dict/set comprehensions → praise as Item 27
- Do not invent problems. If something is genuinely fine, do not flag it as an issue.
- Clearly label any suggestion as optional — use language like "minor suggestion", "stylistic alternative", or "optional improvement", never "issue" or "problem".
- Keep the tone positive — the goal is to affirm and explain why the patterns are good, not to find fault.
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.4license: MIT5---67# Effective Python Skill89Apply 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).1011## Reference Files1213This skill includes categorized reference files with all 90 items:1415- `ref-01-pythonic-thinking.md` — Items 1-10: PEP 8, f-strings, bytes/str, walrus operator, unpacking, enumerate, zip, slicing16- `ref-02-lists-and-dicts.md` — Items 11-18: Slicing, sorting, dict ordering, defaultdict, __missing__17- `ref-03-functions.md` — Items 19-26: Exceptions vs None, closures, *args/**kwargs, keyword-only args, decorators18- `ref-04-comprehensions-generators.md` — Items 27-36: Comprehensions, generators, yield from, itertools19- `ref-05-classes-interfaces.md` — Items 37-43: Composition, @classmethod, super(), mix-ins, public attrs20- `ref-06-metaclasses-attributes.md` — Items 44-51: @property, descriptors, __getattr__, __init_subclass__, class decorators21- `ref-07-concurrency.md` — Items 52-64: subprocess, threads, Lock, Queue, coroutines, asyncio22- `ref-08-robustness-performance.md` — Items 65-76: try/except, contextlib, datetime, decimal, profiling, data structures23- `ref-09-testing-debugging.md` — Items 77-85: TestCase, mocks, dependency injection, pdb, tracemalloc24- `ref-10-collaboration.md` — Items 86-90: Docstrings, packages, root exceptions, virtual environments2526## How to Use This Skill2728**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`).2930---3132## Mode 1: Code Review3334When the user asks you to **review** existing Python code, follow this process:3536### Step 1: Read Relevant References37Determine which chapters apply to the code under review and read those reference files. If unsure, read all of them.3839### Step 2: Calibrate Your Response4041**If the code is already well-written and idiomatic:**42- Say so explicitly and upfront. Do not manufacture issues to appear thorough.43- Praise the good patterns you see (see "Praising Good Patterns" below).44- Any suggestions must be framed as minor optional improvements, not as violations or issues.4546**If the code has real problems:**47- Identify and report them clearly with item references.4849### Step 3: Praise Good Patterns (when present)50When the code uses these patterns correctly, explicitly praise them:5152<strengths_to_praise>53- **`@contextmanager`** for resource management: "Good use of `@contextmanager` (Item 66) — avoids boilerplate try/finally and makes the cleanup intent clear."54- **Generator functions** (`yield`) for memory efficiency: "Good use of a generator (Item 30) — avoids loading the entire sequence into memory."55- **Type annotations** on public functions: "Good use of type annotations (Item 84) — improves readability and enables static analysis."56- **Docstrings** on all public APIs: "Good docstrings (Item 84) — clearly communicates purpose and parameters."57- **`@dataclass`** for plain data holders: "Good use of `@dataclass` (Items 37–43) — reduces boilerplate and provides automatic `__repr__`, `__eq__`."58- **List/dict/set comprehensions** instead of manual loops: "Good use of comprehensions (Item 27) — more readable and Pythonic."59- **`enumerate`** instead of `range(len(...))`: "Good use of `enumerate` (Item 7)."60</strengths_to_praise>6162### Step 4: Analyze the Code for Issues63For each relevant item from the book, check whether the code follows or violates the guideline. Focus on:6465<core_principles>661. **Style and Idiom** (Items 1-10): Is it Pythonic? Does it use f-strings, unpacking, enumerate, zip properly?672. **Data Structures** (Items 11-18): Are lists and dicts used correctly? Is sorting done with key functions?683. **Function Design** (Items 19-26): Do functions raise exceptions instead of returning None? Are args well-structured?694. **Comprehensions & Generators** (Items 27-36): Are comprehensions preferred over map/filter? Are generators used for large sequences?705. **Class Design** (Items 37-43): Is composition preferred over deep nesting? Are mix-ins used correctly? Is `@dataclass` used for plain data holders?716. **Metaclasses & Attributes** (Items 44-51): Are plain attributes used instead of getter/setter methods? Is @property used appropriately?727. **Concurrency** (Items 52-64): Are threads used only for I/O? Is asyncio structured correctly?738. **Robustness** (Items 65-76): Is error handling structured with try/except/else/finally? Are the right data structures chosen?749. **Testing** (Items 77-85): Are tests well-structured? Are mocks used appropriately?7510. **Collaboration** (Items 86-90): Are docstrings present? Are APIs stable?7677### Key Anti-Patterns to Always Check7879<anti_patterns>80- **Mutable default arguments** (Item 24): `def f(items=[])` is a critical bug — the list is shared across all calls. Always use `None` and initialize inside the function body.81 ```python82 # WRONG — shared mutable default83 def process(results=[]):84 results.append(...)8586 # RIGHT — use None sentinel87 def process(results=None):88 if results is None:89 results = []90 results.append(...)91 ```9293- **Bare `except:`** clause (Item 65): `except:` without a type catches `KeyboardInterrupt`, `SystemExit`, and `GeneratorExit`, silently killing the program. Always catch specific exception types: `except (ValueError, KeyError):` or at minimum `except Exception:`.9495- **`for i in range(len(seq))`** (Item 7): Use `for item in seq` directly, or `for i, item in enumerate(seq)` when you need the index.9697- **Manual list-building loops** (Item 27): Any loop that creates an empty list and appends inside the loop body should be a list comprehension.98 ```python99 # WRONG100 result = []101 for x in items:102 if x > 0:103 result.append(x * 2)104105 # RIGHT106 result = [x * 2 for x in items if x > 0]107 ```108109- **Java-style getter/setter methods** (Item 44): `get_name()`, `set_price()`, `get_value()` are non-Pythonic. Access attributes directly or use `@property` when validation is required.110111- **`== True` / `== False` comparisons** (Item 2 / PEP 8): `if x == True:` should be `if x:`. `return self.in_stock == True` should be `return self.in_stock`.112113- **Double-underscore name mangling** (Item 42): `self.__items` makes the attribute inaccessible to subclasses and creates maintenance friction. Use single underscore `self._items` to signal "internal use" without enforced hiding.114115- **Plain data-holder class without `@dataclass`** (Items 37–43): Any class whose `__init__` only assigns parameters to `self.attr` with no logic should be a `@dataclass`. Dataclasses automatically generate `__repr__`, `__eq__`, and `__init__`, and signal the data-holder intent. **Crucially: `@dataclass` and `@property` can coexist.** If one field needs validation, make it a `@property` with a setter inside the `@dataclass`. This is the correct Pythonic pattern — do NOT abandon `@dataclass` just because one field has a validator.116 ```python117 from dataclasses import dataclass, field118119 @dataclass120 class Product:121 name: str122 category: str123 in_stock: bool = True124 _price: float = field(default=0.0, repr=False)125126 @property127 def price(self) -> float:128 return self._price129130 @price.setter131 def price(self, value: float) -> None:132 if value < 0:133 raise ValueError('Price cannot be negative')134 self._price = value135 ```136137- **Missing `__repr__`** (Items 37–43): Any class that is not a `@dataclass` should define `__repr__` to aid debugging. Without it, `repr(obj)` shows only the class name and memory address.138139- **Returning `None` for failure** (Item 20): Functions should raise exceptions for error conditions, not return `None`. Returning `None` forces callers to check for `None` every time and doesn't carry error information.140141- **`else` block after `for`/`while`** (Item 9): The loop-`else` clause fires when the loop completes without a `break`, which is rarely the intended semantics and confuses readers. Avoid it.142</anti_patterns>143</core_principles>144145### Step 5: Report Findings146For each issue found, report:147- **Item number and name** (e.g., "Item 4: Prefer Interpolated F-Strings")148- **Location** in the code149- **What's wrong** (the anti-pattern)150- **How to fix it** (the Pythonic way)151- **Priority**: Critical (bugs/correctness), Important (maintainability), Suggestion (style)152153### Step 6: Provide Fixed Code154Offer a corrected version of the code with all issues addressed, with comments explaining each change.155156---157158## Mode 2: Writing New Code159160When the user asks you to **write** new Python code, follow these principles:161162### Always Apply These Core Practices163164<guidelines>1651. **Follow PEP 8** — Use consistent naming (snake_case for functions/variables, PascalCase for classes). Use `pylint` and `black`-compatible style.1661672. **Use f-strings** for string formatting (Item 4). Never use % or .format() for simple cases.1681693. **Use unpacking** instead of indexing (Item 6). Prefer `first, second = my_list` over `my_list[0]`.1701714. **Use enumerate** instead of range(len(...)) (Item 7).1721735. **Use zip** to iterate over multiple lists in parallel (Item 8). Use `zip_longest` from itertools when lengths differ.1741756. **Avoid else blocks** after for/while loops (Item 9).1761777. **Use assignment expressions** (:= walrus operator) to reduce repetition when appropriate (Item 10).1781798. **Raise exceptions** instead of returning None for failure cases (Item 20).1801819. **Use `None` as the default for mutable default arguments** (Item 24). Never use `[]`, `{}`, or any other mutable object as a default argument value; initialize inside the function body.18218310. **Use keyword-only arguments** for clarity (Item 25). Use positional-only args to separate API from implementation (Item 25).18418511. **Use functools.wraps** on all decorators (Item 26).18618712. **Prefer comprehensions** over map/filter (Item 27). Keep them simple — no more than two expressions (Item 28).18818913. **Use generators** for large sequences instead of returning lists (Item 30).19019114. **Use `@dataclass`** for plain data-holder classes (Items 37–43). A `@dataclass` automatically provides `__init__`, `__repr__`, and `__eq__`, and makes the data-holder intent explicit. Only write a manual `__init__` when you need real logic that a dataclass can't handle. Add `__repr__` to any class that doesn't use `@dataclass`, to make debugging easier.19219315. **Prefer composition** over deeply nested classes (Item 37).19419516. **Use @classmethod** for polymorphic constructors (Item 39).19619717. **Always call super().__init__** (Item 40).19819918. **Use plain attributes** instead of getter/setter methods. Use @property for special behavior (Item 44).20020119. **Use try/except/else/finally** structure correctly (Item 65). Always catch specific exception types, never bare `except:`.20220320. **Write docstrings** for every module, class, and function (Item 84).204</guidelines>205206### Code Structure Template207208<examples>209<example id="1" title="Module and class structure template">210211When writing new modules or classes, follow this structure:212213```python214"""Module docstring describing purpose."""215216# Standard library imports217# Third-party imports218# Local imports219220# Module-level constants221222class MyClass:223 """Class docstring describing purpose and usage.224225 Attributes:226 attr_name: Description of attribute.227 """228229 def __init__(self, param: type) -> None:230 """Initialize with description of params."""231 self.param = param # Use public attributes (Item 42)232233 @classmethod234 def from_alternative(cls, data):235 """Alternative constructor (Item 39)."""236 return cls(processed_data)237238 def method(self, arg: type) -> return_type:239 """Method docstring.240241 Args:242 arg: Description.243244 Returns:245 Description of return value.246247 Raises:248 ValueError: When arg is invalid (Item 20).249 """250 pass251```252</example>253254<example id="2" title="Mutable default argument — correct pattern">255256```python257# WRONG — mutable default causes shared state across all calls258def append_to(element, to=[]):259 to.append(element)260 return to261262# RIGHT — use None sentinel, initialize inside263def append_to(element, to=None):264 if to is None:265 to = []266 to.append(element)267 return to268```269</example>270271<example id="3" title="Plain data holder — use @dataclass, even with @property validation">272273```python274# WRONG — manual __init__ boilerplate for data holder275class Point:276 def __init__(self, x, y):277 self.x = x278 self.y = y279280# RIGHT — @dataclass provides __init__, __repr__, __eq__ for free281from dataclasses import dataclass282283@dataclass284class Point:285 x: float286 y: float287```288289**Important:** `@dataclass` and `@property` are compatible. When one field needs validation, use both — the `@dataclass` handles the boilerplate and the `@property` handles validation. Do NOT fall back to a plain class just because one field has a setter.290291```python292# WRONG — abandoning @dataclass because price needs validation293class Product:294 def __init__(self, name, price, category):295 self.name = name296 self.price = price # validation via set_price()297 self.category = category298299 def set_price(self, value):300 if value < 0:301 raise ValueError("Price cannot be negative")302 self.price = value303304# RIGHT — @dataclass + @property work together305from dataclasses import dataclass, field306307@dataclass308class Product:309 name: str310 category: str311 in_stock: bool = True312 _price: float = field(default=0.0, repr=False)313314 @property315 def price(self) -> float:316 return self._price317318 @price.setter319 def price(self, value: float) -> None:320 if value < 0:321 raise ValueError("Price cannot be negative")322 self._price = value323```324</example>325326<example id="4" title="Getter/setter vs plain attribute and @property">327328```python329# WRONG — Java-style getter/setter330class Temperature:331 def get_celsius(self):332 return self._celsius333334 def set_celsius(self, value):335 if value < -273.15:336 raise ValueError("Temperature below absolute zero")337 self._celsius = value338339# RIGHT — use @property for validation, direct access otherwise340class Temperature:341 def __init__(self, celsius: float) -> None:342 self.celsius = celsius # triggers setter on construction343344 @property345 def celsius(self) -> float:346 return self._celsius347348 @celsius.setter349 def celsius(self, value: float) -> None:350 if value < -273.15:351 raise ValueError("Temperature below absolute zero")352 self._celsius = value353```354</example>355356<example id="5" title="List comprehension vs manual loop">357358```python359# WRONG — manual loop to build list360result = []361for order in orders:362 if order['total'] > threshold:363 result.append(order)364365# RIGHT — list comprehension366result = [order for order in orders if order['total'] > threshold]367```368</example>369</examples>370371### Concurrency Guidelines372373- Use `subprocess` for managing child processes (Item 52)374- Use threads **only** for blocking I/O, never for parallelism (Item 53)375- Use `threading.Lock` to prevent data races (Item 54)376- Use `Queue` for coordinating work between threads (Item 55)377- Use `asyncio` for highly concurrent I/O (Item 60)378- Never mix blocking calls in async code (Item 62)379380### Testing Guidelines381382- Subclass `TestCase` and use `setUp`/`tearDown` (Item 78)383- Use `unittest.mock` for complex dependencies (Item 78)384- Encapsulate dependencies to make code testable (Item 79)385- Use `pdb.set_trace()` or `breakpoint()` for debugging (Item 80)386- Use `tracemalloc` for memory debugging (Item 81)387388---389390## Priority of Items by Impact391392When time is limited, focus on these highest-impact items first:393394### Critical (Correctness & Bugs)395- Item 20: Raise exceptions instead of returning None396- Item 24: Use None as default for mutable arguments (never `[]` or `{}`)397- Item 53: Use threads for I/O only, not parallelism398- Item 54: Use Lock to prevent data races399- Item 40: Initialize parent classes with super()400- Item 65: Use try/except/else/finally correctly; always catch specific exception types401- Item 73: Use datetime instead of time module for timezone handling402403### Important (Maintainability)404- Item 1: Follow PEP 8 style405- Item 4: Use f-strings406- Item 7: Use `for item in seq` or `enumerate`; never `range(len(seq))`407- Item 19: Never unpack more than 3 variables408- Item 25: Use keyword-only and positional-only arguments409- Item 26: Use functools.wraps for decorators410- Items 37–43: Use `@dataclass` for plain data holders; add `__repr__` to any class without it411- Item 42: Prefer public attributes over private; use single underscore for internal412- Item 44: Use plain attributes over getter/setter; use @property for validation413- Item 66: Use `@contextmanager` for reusable resource management patterns414- Item 84: Write docstrings for all public APIs415416### Suggestions (Polish & Optimization)417- Item 8: Use zip for parallel iteration418- Item 10: Use walrus operator to reduce repetition419- Item 27: Use comprehensions over map/filter and manual loops420- Item 30: Use generators for large sequences421- Item 70: Profile before optimizing (cProfile)422423---424425## Reviewing Already-Good Code426427When the submitted code is already idiomatic and well-structured, the review must:4284291. **Lead with affirmative praise** — say explicitly that the code is idiomatic / well-written.4302. **Call out each strong pattern by name and item**, e.g.:431 - `@contextmanager` usage → praise as Item 66432 - Generator functions (`yield`) → praise as Item 30433 - Type annotations on public functions → praise as Item 84434 - Docstrings on public APIs → praise as Item 84435 - `@dataclass` for data holders → praise as Items 37–43436 - List/dict/set comprehensions → praise as Item 274373. **Do not invent problems.** If something is genuinely fine, do not flag it as an issue.4384. **Clearly label any suggestion as optional** — use language like "minor suggestion", "stylistic alternative", or "optional improvement", never "issue" or "problem".4395. **Keep the tone positive** — the goal is to affirm and explain why the patterns are good, not to find fault.