| name | python-patterns |
| description | Effective Python - 90 specific ways to write better Python code |
Brett Slatkin - Effective Python
Apply Brett Slatkin's best practices from "Effective Python: 90 Specific Ways to Write Better Python." Concrete, actionable guidance for professional Python code.
Core Principles
Know the Difference Between Bytes and Str
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
return bytes_or_str.decode('utf-8')
return bytes_or_str
def to_bytes(bytes_or_str):
if isinstance(bytes_or_str, str):
return bytes_or_str.encode('utf-8')
return bytes_or_str
with open('data.txt', 'r', encoding='utf-8') as f:
text = f.read()
with open('data.bin', 'rb') as f:
data = f.read()
Prefer enumerate Over range(len())
for i in range(len(items)):
print(f'{i}: {items[i]}')
for i, item in enumerate(items):
print(f'{i}: {item}')
for i, item in enumerate(items, start=1):
print(f'{i}: {item}')
Use zip to Process Iterators in Parallel
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for i in range(len(names)):
print(f'{names[i]} is {ages[i]}')
for name, age in zip(names, ages):
print(f'{name} is {age}')
from itertools import zip_longest
for name, age in zip_longest(names, ages, fillvalue='?'):
print(f'{name} is {age}')
Prescriptive Rules
Prefer get Over in and KeyError
if key in counters:
count = counters[key]
else:
count = 0
count = counters.get(key, 0)
votes = {}
votes.setdefault(name, []).append(vote)
Use None and Docstrings for Dynamic Default Arguments
def append_to(element, to=[]):
to.append(element)
return to
def append_to(element, to=None):
"""Append element to list.
Args:
element: Item to append
to: Target list. If None, creates new list.
Returns:
List with element appended.
"""
if to is None:
to = []
to.append(element)
return to
Know How Closures Interact with Variable Scope
def create_multipliers():
return [lambda x: x * i for i in range(5)]
multipliers = create_multipliers()
multipliers[2](3)
def create_multipliers():
return [lambda x, i=i: x * i for i in range(5)]
Prefer Generators to Returning Lists
def read_lines(path):
lines = []
with open(path) as f:
for line in f:
lines.append(line.strip())
return lines
def read_lines(path):
with open(path) as f:
for line in f:
yield line.strip()
def read_lines(path):
with open(path) as f:
yield from (line.strip() for line in f)
Know When to Use @property
class Resistor:
def __init__(self, ohms):
self._ohms = ohms
@property
def ohms(self):
return self._ohms
@ohms.setter
def ohms(self, value):
if value < 0:
raise ValueError('Must be >= 0')
self._ohms = value
Prefer Public Attributes Over Private Ones
class MyClass:
def __init__(self):
self.__value = 0
class MyClass:
def __init__(self):
self._value = 0
Use *args for Flexible Function Signatures
def log(message, *values):
if not values:
print(message)
else:
print(f'{message}: {", ".join(str(v) for v in values)}')
log('Hi')
log('Values', 1, 2, 3)
def safe_division(numerator, denominator, *, ignore_zero=False):
if denominator == 0:
if ignore_zero:
return 0
raise ValueError('Cannot divide by zero')
return numerator / denominator
safe_division(10, 2, ignore_zero=True)
Key Patterns
List Comprehensions Over map/filter
result = map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, numbers))
result = [x ** 2 for x in numbers if x % 2 == 0]
result = (x ** 2 for x in numbers if x % 2 == 0)
Use Assignment Expressions (:=) Wisely
if len(data) > 10:
print(f'Data has {len(data)} items')
if (n := len(data)) > 10:
print(f'Data has {n} items')
while (line := file.readline()):
process(line)
Anti-Patterns
| Pattern | Slatkin Fix |
|---|
range(len(x)) | enumerate(x) |
if key in dict: dict[key] | dict.get(key, default) |
| Mutable default argument | None with if None check |
| Return full list | Yield with generator |
__private attributes | _protected convention |
| Nested list comprehension (3+ levels) | Break into loops or functions |
Review Checklist
Key Insight
"Python has a right way and a wrong way to do most things. Effective Python is about learning the right way—not through abstract principles, but through specific, practical techniques you can apply immediately."