Loops are what make programs powerful. Without them, you would need to write one line of code per item -- 10 items means 10 lines, 10,000 items means 10,000 lines. With loops, the same code handles any number of items. Python has elegant loop syntax and several built-in helpers that make common patterns clean and concise.
fruits = ["apple", "mango", "banana", "papaya"]
for fruit in fruits:
print(fruit)
# Iterate string characters
for char in "Python":
print(char)
# Iterate dictionary
person = {"name": "Suraj", "age": 25, "city": "Mumbai"}
for key, value in person.items():
print(f" {key}: {value}")
# Iterate with index using enumerate
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")
for i in range(5): # 0, 1, 2, 3, 4
print(i)
for i in range(1, 6): # 1, 2, 3, 4, 5
print(i)
for i in range(0, 20, 5): # 0, 5, 10, 15
print(i)
for i in range(10, 0, -1): # 10, 9, 8, ... 1 (countdown)
print(i)
# Sum 1 to 100
total = sum(range(1, 101))
print(total) # 5050
names = ["Suraj", "Raj", "Priya"]
scores = [95, 87, 92]
cities = ["Mumbai", "Delhi", "Bangalore"]
for name, score in zip(names, scores):
print(f"{name}: {score}/100")
# Three lists at once
for name, score, city in zip(names, scores, cities):
print(f"{name} from {city}: {score}")
# break -- exit loop when target found
numbers = [3, 7, 2, 9, 1, 5]
target = 9
for num in numbers:
if num == target:
print(f"Found {target}!")
break
print(f"Checking {num}...")
# continue -- skip unwanted items
for n in range(1, 11):
if n % 2 == 0:
continue # Skip even numbers
print(n) # Prints: 1 3 5 7 9
# for-else -- else runs if no break occurred
for num in [1, 3, 5, 7]:
if num % 2 == 0:
print("Found even")
break
else:
print("No even numbers found") # This runs
# Countdown
count = 5
while count > 0:
print(f"Countdown: {count}")
count -= 1
print("Launch!")
# Input validation loop
while True:
raw = input("Enter a positive number: ")
if raw.isdigit() and int(raw) > 0:
number = int(raw)
break
print("Invalid. Try again.")
print(f"Got: {number}")
numbers = range(1, 11)
# Standard loop
squares = []
for n in numbers:
squares.append(n**2)
# Comprehension (same result, one line)
squares = [n**2 for n in numbers]
evens = [n for n in numbers if n % 2 == 0]
print(squares) # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
print(evens) # [2, 4, 6, 8, 10]
# Dict comprehension
word_lengths = {w: len(w) for w in ["Python", "Docker", "Linux"]}
print(word_lengths) # {Python: 6, Docker: 6, Linux: 5}
# Set comprehension
first_letters = {w[0] for w in ["Python", "Perl", "Docker"]}
print(first_letters) # {P, D}
Use for when iterating over a known collection or range. Use while when the loop must continue until a condition changes -- like reading input until valid data is received.
range(stop) generates 0 to stop-1. range(start, stop) generates start to stop-1. range(start, stop, step) with step increment. range() is lazy -- it generates numbers on demand without creating a full list in memory.
break immediately exits the loop. continue skips the rest of the current iteration and moves to the next one. Both work in for and while loops.
enumerate(iterable) yields (index, value) pairs. for i, item in enumerate(my_list) gives both index and value without maintaining a manual counter. Start counting from 1 with enumerate(items, start=1).
[expression for item in iterable if condition] creates a new list. More readable and often faster than a loop appending to a list. Keep them simple and readable -- complex logic belongs in a regular loop.
In Part 6, we go deeper on data structures -- advanced list techniques, dict patterns, and the collections module.
def read_large_file(filepath):
"""Process large files without loading everything into memory."""
with open(filepath) as f:
for line in f:
yield line.strip() # Generator -- one line at a time
# Process 10GB log file without running out of memory
for line in read_large_file("/var/log/massive.log"):
if "ERROR" in line:
print(line)
# Generator expressions (like list comprehensions but lazy)
error_lines = (line for line in read_large_file("app.log") if "ERROR" in line)
first_10_errors = list(itertools.islice(error_lines, 10))
import itertools
# Chain multiple iterables
combined = list(itertools.chain([1,2,3], [4,5,6], [7,8,9]))
print(combined) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
# Generate all combinations
skills = ["Python", "Docker", "K8s"]
for combo in itertools.combinations(skills, 2):
print(combo)
# ('Python', 'Docker'), ('Python', 'K8s'), ('Docker', 'K8s')
# Chunk a list into batches
def batched(iterable, n):
it = iter(iterable)
while batch := list(itertools.islice(it, n)):
yield batch
items = list(range(1, 25))
for batch in batched(items, 5):
print(f"Processing batch: {batch}")