For & While Loops
for (iterate over sequences) and while (repeat while condition is true). The range() function in depth. Loop control with break, continue, and pass. Nested loops, enumerate(), zip(), and the loop-else clause.
Two Types of Loops
Loops let your program repeat a block of code without you having to write it multiple times. Python has exactly two loop types — each suited to different situations.
The for Loop
A for loop steps through each item in a sequence one by one, assigning it to a variable you name. When the sequence is exhausted, the loop ends automatically.
# Looping over a list fruits = ["apple", "banana", "mango"] for fruit in fruits: print(f"I like {fruit}") # I like apple # I like banana # I like mango # Looping over a string (character by character) for char in "Python": print(char, end="-") # P-y-t-h-o-n- print() # newline # Summing numbers in a list marks = [85, 72, 91, 68, 77] total = 0 for mark in marks: total += mark print(f"Total: {total}, Average: {total/len(marks):.1f}") # Total: 393, Average: 78.6 # Loop variable scope — it persists after the loop for i in [10, 20, 30]: pass print(i) # 30 — last value assigned
The range() Function
range() generates a sequence of numbers on demand — without storing them all in memory. It's the most common companion to for loops when you need a counter.
| Call | Generates | Description |
|---|---|---|
| range(5) | 0, 1, 2, 3, 4 | 0 up to (not including) 5 |
| range(1, 6) | 1, 2, 3, 4, 5 | start=1, stop=6 (exclusive) |
| range(0, 10, 2) | 0, 2, 4, 6, 8 | step=2 (every other) |
| range(10, 0, -1) | 10, 9, 8, …, 1 | countdown (negative step) |
| range(0, 0) | (empty) | start == stop → no iterations |
# Print 1 to 5 for i in range(1, 6): print(i, end=" ") # 1 2 3 4 5 print() # Countdown from 5 for i in range(5, 0, -1): print(i, end=" ") # 5 4 3 2 1 print("🚀") # Sum of 1 to 100 total = 0 for n in range(1, 101): total += n print(total) # 5050 # Times table n = 7 for i in range(1, 11): print(f"{n} × {i:2} = {n*i:3}")
The while Loop
A while loop repeats its body as long as its condition remains True. The condition is checked before each iteration — if it's already False at the start, the body never runs.
Critical: Something inside the loop must eventually make the condition False, or the loop runs forever (an infinite loop). Always ensure your while condition will eventually become false.
# Basic while count = 1 while count <= 5: print(count, end=" ") count += 1 # ← MUST update or infinite loop! # 1 2 3 4 5 # Keep asking until valid input — very common pattern age = -1 while age < 0 or age > 120: age = int(input("Enter valid age (0-120): ")) if age < 0 or age > 120: print(" ❌ Invalid. Try again.") print(f"Age accepted: {age}") # PIN retry system — limited attempts CORRECT = 1234 attempts = 0 MAX = 3 while attempts < MAX: pin = int(input(f"PIN (attempt {attempts+1}/{MAX}): ")) attempts += 1 if pin == CORRECT: print("✅ Access granted!") break else: print("🔒 Account locked.") # only runs if loop ended without break
count += 1), or a condition that can never become False. Always ask: "what will eventually make this False?"Loop Control — break, continue, pass
Three special keywords give you fine-grained control over loop execution.
# break — exit loop early numbers = [3, 7, 12, 5, 9] for n in numbers: if n % 2 == 0: print(f"First even number: {n}") break # found it — stop searching # First even number: 12 # continue — skip current iteration for i in range(1, 11): if i % 2 == 0: continue # skip even numbers print(i, end=" ") # 1 3 5 7 9 print() # pass — empty placeholder for i in range(5): if i == 3: pass # TODO: handle this case later print(i, end=" ") # 0 1 2 3 4 (pass does nothing) # Loop-else: else runs only if loop completed without break target = 99 for n in [10, 20, 30]: if n == target: print("Found!") break else: print("Not found in list.") # runs — no break triggered
for/while loops can have an else clause. It runs only if the loop finished without hitting a break. This is perfect for search operations: the else means "not found". Most Python developers don't know this exists — knowing it sets you apart.enumerate() & zip()
Two built-in functions that make for loops dramatically more powerful and Pythonic — eliminating the need for manual counter variables.
# enumerate() — loop with an automatic counter fruits = ["apple", "banana", "mango"] # Old way (avoid this): i = 0 for fruit in fruits: print(i, fruit); i += 1 # Pythonic way with enumerate: for idx, fruit in enumerate(fruits): print(f"{idx}: {fruit}") # 0: apple 1: banana 2: mango # enumerate with custom start for num, fruit in enumerate(fruits, start=1): print(f"{num}. {fruit}") # 1. apple 2. banana 3. mango # ────────────────────────────────────────────── # zip() — loop over two lists simultaneously names = ["Ali", "Sara", "Zara"] scores = [88, 95, 72] for name, score in zip(names, scores): grade = "A" if score >= 80 else "B" print(f"{name:8} {score} Grade: {grade}") # Ali 88 Grade: A # Sara 95 Grade: A # Zara 72 Grade: B
Nested Loops
A loop inside another loop is called a nested loop. The inner loop runs completely for each single iteration of the outer loop. Nested loops are essential for working with grids, tables, matrices, and patterns.
# Multiplication grid for row in range(1, 4): for col in range(1, 4): print(f"{row*col:3}", end="") print() # 1 2 3 # 2 4 6 # 3 6 9 # Star pattern for i in range(1, 6): print("★" * i) # ★ # ★★ # ★★★ # ★★★★ # ★★★★★ # Nested loop with break — search a 2D grid grid = [[1,2,3],[4,5,6],[7,8,9]] target = 5 for row_idx, row in enumerate(grid): for col_idx, val in enumerate(row): if val == target: print(f"Found {target} at row {row_idx}, col {col_idx}") break # breaks inner loop only # Found 5 at row 1, col 1
break only exits the innermost loopbreak only exits the loop it's directly inside — not the outer loop. To exit both, you can use a flag variable (found = True; break then check if found: break in outer loop) or wrap in a function and use return.Choosing: for vs while
for whenrange(N).while whenfor loops over while when iterating. If you catch yourself doing i=0; while i < len(lst), switch to for item in lst.range(2, 10, 3) generate?continue do inside a loop?enumerate(["a","b","c"], start=1) yield on the first iteration?else clause of a for loop execute?for i in range(3):
for j in range(4):
print(i, j)1. Uses a while loop to keep asking the user for numbers until they type
done2. Stores valid numbers in a list; skips non-numeric entries using
continue3. After collecting numbers, uses a for loop with enumerate to print each number with its position
4. Calculates and prints: total, average, maximum, minimum, and count of even numbers
5. Uses a for-else to check if any number is greater than 100 (print "Found!" or "None above 100")
6. Prints all numbers in reverse order using
range with a negative step
💡 Show hints
- Use
entry.replace('.','',1).isdigit()to check if a string is a valid number numbers = []starts an empty list; usenumbers.append(val)to add- Reverse:
for i in range(len(numbers)-1, -1, -1) - Even count: use
continuefor odds, orsum(1 for n in numbers if n%2==0)
# ── Number Analysis Engine ──────────────────── numbers = [] print("Enter numbers one by one. Type 'done' to finish.") while True: entry = input("Number: ").strip() if entry.lower() == "done": break if not entry.replace(".", "", 1).lstrip("-").isdigit(): print(" ❌ Not a number — skipping.") continue numbers.append(float(entry)) if not numbers: print("No numbers entered.") else: print(f"\n{'─'*34}") # Print with position for idx, n in enumerate(numbers, 1): print(f" {idx}. {n:g}") # Statistics total = sum(numbers) avg = total / len(numbers) evens = sum(1 for n in numbers if n % 2 == 0) print(f"\n Count : {len(numbers)}") print(f" Total : {total:g}") print(f" Average : {avg:.2f}") print(f" Max : {max(numbers):g}") print(f" Min : {min(numbers):g}") print(f" Evens : {evens}") # For-else: check for > 100 for n in numbers: if n > 100: print(f" Found number > 100: {n:g}") break else: print(" None above 100.") # Reverse print print(" Reversed:", end=" ") for i in range(len(numbers) - 1, -1, -1): print(numbers[i], end=" ")