All chapters in this track
- 011. Variables, Types & Operators
- 022. Strings
- 033. Lists
- 044. Tuples, Sets & Dicts
- 055. Control Flow
- 066. Error Handling
- 077. Functions & Lambdas
- 088. Comprehensions
- 099. Built-in Functions
- 1010. Type Hints (3.10+)
- 1111. Classes & Dataclasses
- 1212. Iterators & Generators
- 1313. DSA Standard Library
- 1414. Python 3.9–3.11 Features for DSA
- 1515. DSA Idioms & Gotchas
- 1616. Master Quick Reference
Chapter 5 of 16
5. Control Flow
Tutorial
Python's control flow has a few DSA-critical patterns: for/else, short-circuit evaluation, and chained comparisons.
# ══ IF / ELIF / ELSE ════════════════════════════════════════════
x = 10
if x > 0:
print("positive")
elif x < 0:
print("negative")
else:
print("zero")
# Ternary
result = "even" if x % 2 == 0 else "odd"
safe = node.val if node else 0 # null-guard
# ══ FOR LOOPS ═══════════════════════════════════════════════════
for i in range(n): # 0..n-1
pass
for i in range(n-1, -1, -1): # n-1 down to 0
pass
for i, val in enumerate(arr): # index + value
pass
for a, b in zip(arr1, arr2): # parallel iteration
pass
# Python 3.10+: zip(strict=True) — raises ValueError if unequal lengths
for a, b in zip(arr1, arr2, strict=True):
pass
# Skip duplicates in sorted array (common backtracking pattern)
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i-1]:
continue
# process nums[i]
# for / else — else runs only if loop completed WITHOUT break
for node in graph[start]:
if node == target:
print("found"); break
else:
print("not found") # only runs if break was never hit
# ══ PASS / CONTINUE / BREAK ═════════════════════════════════════
pass # do nothing — placeholder for empty blocks
continue # skip rest of loop body, go to next iteration
break # exit the loop entirely
# ══ WHILE LOOPS ═════════════════════════════════════════════════
l, r = 0, len(arr) - 1
while l < r: # two-pointer pattern
l += 1; r -= 1
# Infinite loop with break
while True:
val = get_next()
if val is None:
break
process(val)
# ══ WALRUS OPERATOR := (Python 3.8+) ════════════════════════════
# Assign + use a value in the same expression — avoids recomputation
while (n := len(stack)) > 0: # capture and test len()
stack.pop()
if (val := cache.get(key)) is not None: # fetch + check in one line
use(val)
# Handy inside comprehensions — compute once, reuse
results = [y for x in data if (y := transform(x)) > 0]
# Reading chunks until exhausted
while chunk := file.read(1024):
process(chunk)
# Walking a linked list without a separate lookahead variable
cur = head
while (nxt := cur.next) is not None:
process(cur)
cur = nxt
# ══ MATCH / CASE (Python 3.10+) ════════════════════════════════
# Structural pattern matching — cleaner than long if/elif chains
command = "go north"
match command.split():
case ["go", direction]:
print(f"Going {direction}")
case ["quit"]:
print("Quitting")
case _:
print("Unknown command")
# Match with values (useful for state machines in DSA)
def handle(state: int, event: str) -> str:
match (state, event):
case (0, "start"): return "running"
case (1, "pause"): return "paused"
case (1, "stop"): return "stopped"
case _: return "unknown"
Reference
| Construct | Syntax | Notes |
|---|---|---|
| Range forward | range(n) | 0 to n-1 |
| Range backward | range(n-1,-1,-1) | n-1 down to 0 |
| Index + value | enumerate(lst) | |
| Parallel iter | zip(a, b) | |
| Strict zip | zip(a,b,strict=True) | 3.10+ raises on length mismatch |
| for/else | for … else: | else skipped if break hit |
| Ternary | a if cond else b | |
| Null guard | node and node.val | Short-circuit |
| Pattern match | match x: case …: | 3.10+ |
| Skip duplicate | if i>0 and a[i]==a[i-1]: continue | Sorted array dedup |
| Walrus assign | (x := expr) | 3.8+; assigns and returns value in one expression |