18. Common Interview Pitfalls & Patterns
Know the classics; avoid traps that signal weak fundamentals.
Question: Why are mutable default arguments a problem in Python?
Answer: Default arguments are evaluated only once, when the function is defined, not each time it's called. If a mutable object like a list or dictionary is used as a default, it will be shared across all calls to that function, leading to unexpected behavior.
Explanation: The standard pattern to avoid this is to use None
as the default and then create a new mutable object inside the function if the argument is None
.
# Correct way to handle mutable defaults
def f(x, acc=None):
if acc is None:
acc = []
acc.append(x)
return acc
Question: What is late-binding in closures and how can it cause issues in loops?
Answer: Closures in Python bind to names, not values. In a loop, if a lambda or inner function captures a loop variable, it will see the final value of that variable from the loop's last iteration, not the value it had when the function was defined.
Explanation: The classic solution is to force an early binding by passing the loop variable as a default argument to the inner function. This creates a new scope and captures the value at that specific iteration.
# The `i=i` captures the value of i at each iteration
funcs = [lambda x, i=i: x + i for i in range(3)]
# funcs[0](10) returns 10, not 12
Question: What are timezone pitfalls with
datetime
and how to avoid them?
Answer: Naive datetimes lack timezone info and cause bugs. Use aware datetimes (zoneinfo
) and store UTC in persistence layers.
Explanation: Convert to local time only at the edges.
from datetime import datetime, timezone
utc_now = datetime.now(tz=timezone.utc)
Question: Why can iterators be exhausted unexpectedly?
Answer: Many APIs consume iterators; reusing them later yields nothing. Materialize when needed.
Explanation: Prefer sequences for multiple passes.
it = (x for x in range(3))
list(it); list(it) # second list(it) == []
Question: What are floating-point pitfalls?
Answer: Binary floats cannot exactly represent many decimals; comparisons can be surprising.
Explanation: Use tolerances or decimal for money.
from math import isclose
isclose(0.1 + 0.2, 0.3, rel_tol=1e-9)