Python Loops: for, while, nested
Python Loops Interview Questions
| Aspect | for loop | while loop |
|---|---|---|
| When to use | When you know number of iterations | When iterations depend on condition |
| Initialization | Automatic (gets next item) | Manual (before loop) |
| Condition | Implied (items in iterable) | Explicit (boolean expression) |
| Increment | Automatic (next iteration) | Manual (inside loop) |
| Risk | No infinite loop (finite iterable) | Risk of infinite loop |
Runs when the loop finishes without break. If you break, the else is skipped—useful for “not found” patterns with flags.
Use enumerate(xs) for clarity and speed—avoids range/len noise and off-by-one mistakes.
Second loop runs zero times—generators are single-use iterators. Use list(gen) or rebuild if you need multiple passes.
Skipping or double-processing elements; indices shift. Iterate over a copy or build a new list, or use comprehension filters.
Equivalent if structured well—while True suits mid-loop exit after partial work; keep exit conditions obvious.
Often O(n²) if both go to n—interviewers probe whether you can reduce with sorting, hashing, or two-pointer techniques.
Safely take first N without materializing infinite lists—stops your loop from hanging in generator pipelines.
Shortest by default in Python 3—extra items in longer iterables are ignored. Use itertools.zip_longest to pad.
Inner i shadows outer; after loops, i is last inner value—can confuse readers and leak values.
Keys in insertion order (3.7+). Use .values() or .items() explicitly to avoid wrong assumptions.
Memory: generator streams values without building a list—matters for large n inside loops or aggregations.
Convention for unused variable—silences linters. Still iterates; some style guides prefer explicit name if count matters for debugging.
finally still runs before leaving the loop—resources clean up. Order vs else on loop matters: understand execution table.
Same complexity classes—but recursion hits Python’s recursion depth limit; iterative or explicit stacks avoid overflow.
Cooperative multitasking over async iterators—I/O concurrency differs from threading—don’t mix blocking calls inside async loops.
Comprehensions often faster (run in C-level interpreter paths) and clearer—unless complex side effects (avoid side effects in comps).
Masks bugs like KeyboardInterrupt; catches everything silently—breaks flow debugging especially in long-running loops.
Innermost loop only—use flags or refactor functions if you need to continue outer iterator.
Rounding drift may skip termination—prefer integers scaled by factor or math.isclose.
Reads lazily—memory efficient for huge files. Don’t seek elsewhere mid-loop without understanding buffering.
popleft() O(1)—lists shifting from front are O(n). Complexity interviews favor deque for queue-like loops.
The walrus operator assigns and tests in one expression—fewer duplicated reads and a tighter loop header.
# Walrus: assign chunk, then test truthiness
with open(path, "rb") as f:
while chunk := f.read(8192):
process(chunk)
# Classic equivalent
with open(path, "rb") as f:
chunk = f.read(8192)
while chunk:
process(chunk)
chunk = f.read(8192)Python’s sorted/list.sort are stable—tie-breaking passes preserve relative order; matters multi-key sorting pipelines.
Timing tiny snippets includes interpreter overhead—use meaningful workloads; beware JIT-less Python vs PyPy differences.
If branch prediction misses dominate rare exits—but Python-level loops rarely optimize at that hardware nuance; clarity wins.
Both reverse iteration—range(n-1,-1,-1) explicit step works too—pick readability.
if bad: continue flattens happy-path logic—fewer bugs than deeply nested valid cases.
Accidentally O(n² log n) if sorting each iteration—sort once outside when possible.
Ranges are reusable lightweight sequences—safe unlike generators.
Silent truncation—validate lengths match when pairing parallel sequences or assert equality upfront.