15. Top Pitfalls
Common mistakes that cause subtle bugs—recognize and avoid them quickly.
Mutable default arguments
Bad creates shared state across calls; use
None
and create inside.def add_item(x, bag=[]): # BAD bag.append(x) return bag def add_item_safe(x, bag=None): # GOOD if bag is None: bag = [] bag.append(x) return bag
List multiplication with inner lists
grid = [[0]*3]*3 # BAD: rows share the same list grid[0][0] = 1 # mutates all rows grid = [[0 for _ in range(3)] for _ in range(3)] # GOOD
Floating point equality
0.1 + 0.2 == 0.3 # False import math math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-9) # True
Late binding in closures (loop variables)
funcs = [lambda i=i: i*i for i in range(3)] # default arg captures value [f() for f in funcs] # [0, 1, 4]
Shadowing built-ins
Avoid names like
list
,dict
,id
,type
for your variables.Overbroad exception handling
try: risky() except Exception: # BAD: hides bugs pass try: risky() except (ValueError, KeyError) as e: # GOOD: handle expected cases handle(e)
File encodings/newlines
Always set
encoding="utf-8"
. For CSV on Windows, passnewline=""
to avoid blank lines.Off-by-one slicing
Remember end index is exclusive:
s[a:b]
includesa
, excludesb
.Using
is
for value comparisonUse
==
for equality,is
only for identity (None
, singletons).HTTP without timeouts
requests.get(url, timeout=5) # always set a timeout