Control FlowPython Loops
A loop lets you execute a block of code repeatedly — either a fixed number of times, or as long as a condition is true. Without loops, you would have to write the same code manually for every single item you want to process.
Python has two types of loops: the for loop, which iterates over a sequence, and the while loop, which keeps running as long as a condition is True. Knowing which one to reach for in a given situation is a key programming skill.
The for Loop
The for loop iterates over every item in a sequence — a list, string, tuple, set, dictionary, or range. On each iteration, the loop variable takes the value of the next item.
languages = ["Python", "JavaScript", "Go", "Rust"]
for lang in languages:
print(f"I am learning {lang}")
# Looping over a string
for char in "Hello":
print(char)
OutputI am learning Python
I am learning JavaScript
I am learning Go
I am learning Rust
H
e
l
l
o
The range() Function
The range() function generates a sequence of numbers. It is the standard way to repeat code a specific number of times. It takes up to three arguments: start, stop, and step.
# range(stop) — from 0 to stop-1
for i in range(5):
print(i)
print("---")
# range(start, stop)
for i in range(2, 7):
print(i)
print("---")
# range(start, stop, step)
for i in range(0, 20, 5):
print(i)
# Counting backwards
for i in range(10, 0, -1):
print(i, end=" ")
Output0
1
2
3
4
---
2
3
4
5
6
---
0
5
10
15
10 9 8 7 6 5 4 3 2 1
The while Loop
The while loop keeps executing its body as long as the condition evaluates to True. It is used when you do not know in advance how many iterations you need.
attempts = 0
max_attempts = 3
while attempts < max_attempts:
print(f"Attempt {attempts + 1}: trying to connect...")
attempts += 1
print("Max attempts reached. Connection failed.")
OutputAttempt 1: trying to connect...
Attempt 2: trying to connect...
Attempt 3: trying to connect...
Max attempts reached. Connection failed.
💡Critical Warning: Always make sure the while loop condition will eventually become False. If it never does, you have an infinite loop — your program will run forever and freeze. Always ensure the loop variable is being modified inside the loop body.
The break Statement
The break statement immediately exits the loop, regardless of whether the loop condition is still True or there are more items to iterate. Execution jumps to the first line after the loop.
emails = ["alice@x.com", "bob@x.com", "INVALID", "charlie@x.com"]
for email in emails:
if email == "INVALID":
print(f"Bad data found: {email}. Stopping processing.")
break
print(f"Sending email to: {email}")
print("Loop ended.")
OutputSending email to: alice@x.com
Sending email to: bob@x.com
Bad data found: INVALID. Stopping processing.
Loop ended.
The continue Statement
The continue statement skips the rest of the current iteration and jumps directly to the next one. The loop itself does not stop — only the current pass through is cut short.
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Print only odd numbers — skip all even ones
for n in numbers:
if n % 2 == 0:
continue # Skip even numbers
print(n)
Output1
3
5
7
9
The else Clause on Loops
Python loops have a unique feature not found in most languages: an else clause. The else block runs after the loop finishes normally — but it is skipped if the loop was exited via a break. This is perfect for "search and report" patterns.
users = ["alice", "bob", "charlie"]
target = "diana"
for user in users:
if user == target:
print(f"Found user: {target}")
break
else:
print(f"User '{target}' not found in the database.")
OutputUser 'diana' not found in the database.
Nested Loops
A nested loop is a loop inside another loop. The inner loop runs its full cycle for every single iteration of the outer loop. They are essential for working with 2D data like grids, tables, and matrices.
# Multiplication table (3x3)
for row in range(1, 4):
for col in range(1, 4):
print(f"{row} x {col} = {row * col}")
print("---")
Output1 x 1 = 1
1 x 2 = 2
1 x 3 = 3
---
2 x 1 = 2
2 x 2 = 4
2 x 3 = 6
---
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
---
enumerate() and zip()
enumerate() adds a counter to any iterable, giving you both the index and the value on each iteration. zip() pairs up items from two or more iterables, iterating them in parallel.
fruits = ["apple", "banana", "cherry"]
prices = [1.20, 0.50, 2.00]
# enumerate — index + value
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")
print("---")
# zip — iterate two lists in parallel
for fruit, price in zip(fruits, prices):
print(f"{fruit}: ${price}")
Output1. apple
2. banana
3. cherry
---
apple: $1.2
banana: $0.5
cherry: $2.0