Sources:
- PEP 8: https://peps.python.org/pep-0008/
- PEP 20: https://peps.python.org/pep-0020/
- Google Python Style Guide: https://google.github.io/styleguide/pyguide.html
- Effective Python, 3rd ed. (Brett Slatkin, Addison-Wesley, 2024, ISBN 978-0138172183)
Each pattern notes its primary source. Item numbers reference the 3rd edition.
Source: Effective Python Item 17, PEP 279
# No
for i in range(len(items)):
print(i, items[i])
# Yes
for i, item in enumerate(items):
print(i, item)Source: Effective Python Item 18
# No
for i in range(min(len(names), len(colors))):
print(names[i], colors[i])
# Yes
for name, color in zip(names, colors):
print(name, color)Source: PEP 322
# No
for i in range(len(items) - 1, -1, -1):
print(items[i])
# Yes
for item in reversed(items):
print(item)Source: Effective Python Item 40, PEP 202
# No
result = list(map(lambda x: x * 2, filter(lambda x: x > 0, items)))
# Yes
result = [x * 2 for x in items if x > 0]Source: Effective Python Item 44, PEP 289
# No -- builds entire list in memory
total = sum([x**2 for x in range(10**6)])
# Yes -- lazy evaluation
total = sum(x**2 for x in range(10**6))Source: PEP 343, Effective Python Item 82
# No
f = open("data.txt")
try:
data = f.read()
finally:
f.close()
# Yes
with open("data.txt") as f:
data = f.read()Source: Effective Python Items 35, 37
# No -- what do these booleans mean?
search("@obama", False, 20, True)
# Yes
search("@obama", retweets=False, count=20, popular=True)Source: PEP 557, Effective Python Item 51
# No
result = (0, 4) # what are these?
# Yes
from dataclasses import dataclass
@dataclass
class TestResults:
failed: int
attempted: intSource: Core Python feature
# No
temp = y
y = x + y
x = temp
# Yes
x, y = y, x + ySource: PEP 8, Google Style Guide
# No -- O(n^2) string building
s = names[0]
for name in names[1:]:
s += ", " + name
# Yes -- O(n)
s = ", ".join(names)Source: Effective Python Item 27, Python docs collections module
# No
d = {}
for color in colors:
if color not in d:
d[color] = 0
d[color] += 1
# Yes
from collections import Counter
d = Counter(colors)Source: Effective Python Item 4
# No -- hard to read
value = first if first is not None else (second if second is not None else default)
# Yes
def first_valid(*values, default=None):
return next((v for v in values if v is not None), default)
value = first_valid(first, second, default=default)Source: Effective Python Item 32
# No -- caller can't distinguish None result from error
def divide(a, b):
if b == 0:
return None
return a / b
# Yes
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / bSource: Effective Python Item 43, PEP 255
# No -- builds entire list in memory
def read_lines(path):
results = []
with open(path) as f:
for line in f:
results.append(line.strip())
return results
# Yes -- yields one at a time
def read_lines(path):
with open(path) as f:
for line in f:
yield line.strip()Source: Effective Python Item 58, PEP 8
# No -- Java-style boilerplate
class User:
def __init__(self, name):
self._name = name
def get_name(self):
return self._name
def set_name(self, name):
self._name = name
# Yes -- use @property only when you need computed access
class User:
def __init__(self, name):
self.name = nameSource: Python docs functools module, Effective Python Item 38
# No
_cache = {}
def fib(n):
if n in _cache:
return _cache[n]
result = fib(n - 1) + fib(n - 2) if n > 1 else n
_cache[n] = result
return result
# Yes (Python 3.9+: use @cache for unbounded, @lru_cache for bounded)
from functools import cache
@cache
def fib(n):
return fib(n - 1) + fib(n - 2) if n > 1 else nSource: Effective Python Item 48
# No -- single-method class is a function in disguise
class Validator:
def validate(self, value):
return value > 0
# Yes
def validate(value):
return value > 0Source: Effective Python Item 36, Google Style Guide 2.12
# No -- shared mutable state across calls
def append_to(element, target=[]):
target.append(element)
return target
# Yes
def append_to(element, target=None):
if target is None:
target = []
target.append(element)
return target