Loops & Comprehensions

Loops & Comprehensions

Python's loops and comprehensions let you process collections of data concisely and expressively. List comprehensions in particular are one of the most loved Python features — they let you transform and filter data in a single readable line.

Why This Chapter Matters

You will process lists, files, API responses, and database results constantly. Knowing all the loop tools Python provides — and when to use comprehensions vs explicit loops — is a core professional skill.

for Loops Deep Dive

Looping with range()

# Basic counting
for i in range(10):
    print(i)   # 0 to 9

# From 1 to 10 inclusive
for i in range(1, 11):
    print(i)

# Every 3rd number
for i in range(0, 30, 3):
    print(i)   # 0, 3, 6, 9, 12, 15, 18, 21, 24, 27

# Counting down
for i in range(10, 0, -1):
    print(i)   # 10, 9, 8, ..., 1

enumerate() — Loop with Index

names = ["Asha", "Leo", "Mina"]

for index, name in enumerate(names):
    print(f"{index + 1}. {name}")
# Output:
# 1. Asha
# 2. Leo
# 3. Mina

zip() — Loop Over Multiple Iterables Together

names = ["Asha", "Leo", "Mina"]
scores = [95, 88, 92]

for name, score in zip(names, scores):
    print(f"{name}: {score}")

zip() stops at the shortest iterable. Use zip_longest from itertools if you need to go to the longest.

reversed() — Iterate Backwards

items = [1, 2, 3, 4, 5]

for item in reversed(items):
    print(item)   # 5, 4, 3, 2, 1

sorted() — Iterate in Sorted Order

fruits = ["banana", "apple", "cherry"]

for fruit in sorted(fruits):
    print(fruit)   # alphabetical order

while Loops Deep Dive

Basic while Loop

attempts = 0
max_attempts = 3

while attempts < max_attempts:
    password = input("Enter password: ")
    if password == "secret123":
        print("Access granted!")
        break
    attempts += 1
    print(f"Wrong! {max_attempts - attempts} attempts left.")
else:
    print("Account locked.")

Infinite Loop with break

while True:
    command = input("Enter command (or 'exit'): ")
    if command == "exit":
        break
    print(f"You typed: {command}")

This pattern is common in interactive programs and menu systems.

List Comprehensions

A list comprehension creates a new list by applying an expression to each item.

Basic Syntax

result = [expression for item in iterable]

Examples

# Squares of 1–10
squares = [x ** 2 for x in range(1, 11)]
print(squares)   # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# Uppercase all names
names = ["asha", "leo", "mina"]
upper_names = [name.upper() for name in names]

# Convert temperatures
celsius = [0, 20, 37, 100]
fahrenheit = [(c * 9/5) + 32 for c in celsius]
print(fahrenheit)   # [32.0, 68.0, 98.6, 212.0]

With a Condition (Filter)

result = [expression for item in iterable if condition]
numbers = range(1, 21)

# Only even numbers
evens = [n for n in numbers if n % 2 == 0]
print(evens)   # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

# Long words only
words = ["cat", "elephant", "dog", "hippopotamus", "ox"]
long_words = [w for w in words if len(w) > 4]
print(long_words)   # ['elephant', 'hippopotamus']

Nested List Comprehension

# Flatten a 2D list
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(flat)   # [1, 2, 3, 4, 5, 6, 7, 8, 9]

# Pairs of (row, col)
pairs = [(r, c) for r in range(3) for c in range(3)]

Dictionary Comprehensions

Create dictionaries in a single expression:

# Squares as a dict
squares = {n: n**2 for n in range(1, 6)}
print(squares)   # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# Invert a dictionary
original = {"a": 1, "b": 2, "c": 3}
inverted = {v: k for k, v in original.items()}
print(inverted)   # {1: 'a', 2: 'b', 3: 'c'}

# Filter a dictionary
scores = {"Asha": 95, "Leo": 70, "Mina": 88}
top = {name: score for name, score in scores.items() if score >= 80}
print(top)   # {'Asha': 95, 'Mina': 88}

Set Comprehensions

numbers = [1, 2, 2, 3, 3, 3, 4]
unique_squares = {n**2 for n in numbers}
print(unique_squares)   # {1, 4, 9, 16} — duplicates removed

Generator Expressions

Generator expressions are like list comprehensions but they produce values one at a time, using almost no memory.

# List comprehension — builds entire list in memory
total = sum([x**2 for x in range(1_000_000)])

# Generator expression — computes one at a time
total = sum(x**2 for x in range(1_000_000))   # note: no square brackets

Use generator expressions when you only need to iterate once and do not need the whole list stored.

Practical Patterns

Transform and Filter in One Step

students = [
    {"name": "Asha", "score": 95},
    {"name": "Leo", "score": 70},
    {"name": "Mina", "score": 88}
]

passing_names = [s["name"] for s in students if s["score"] >= 80]
print(passing_names)   # ['Asha', 'Mina']

Counting with a Loop

text = "hello world"
vowels = "aeiou"
count = sum(1 for char in text if char in vowels)
print(count)   # 3

When to Use Comprehensions vs Explicit Loops

SituationRecommendation
Simple transform or filterComprehension
Multiple steps or complex logicExplicit for loop
Side effects (printing, etc.)Explicit for loop
Building a large list onceComprehension
Streaming large dataGenerator expression

A readable comprehension is great. An unreadable three-condition nested comprehension is not.

Common Mistakes

  • using comprehensions for side effects ([print(x) for x in items] — use a loop instead)
  • creating a list comprehension when a generator expression would save memory
  • overly long comprehensions that sacrifice readability
  • forgetting that for x in range(n) gives 0 to n–1, not n

Mini Exercises

  1. Use a list comprehension to get all multiples of 5 between 1 and 100.
  2. Use zip() to pair two lists and compute the sum of each pair.
  3. Use enumerate() to print each item in a list with a 1-based number.
  4. Write a dictionary comprehension that maps each word to its length.
  5. Rewrite [n for n in range(100) if n % 3 == 0 and n % 5 == 0] using a generator and sum.

Review Questions

  1. What is the difference between a list comprehension and a generator expression?
  2. What does enumerate() return and why is it useful?
  3. How does zip() behave when iterables have different lengths?
  4. When should you prefer an explicit for loop over a comprehension?
  5. Write a dictionary comprehension that keeps only entries where the value is greater than 0.

Reference Checklist

  • I can use range(), enumerate(), zip(), reversed(), and sorted() in loops
  • I can write list, dict, and set comprehensions with filters
  • I understand the difference between comprehensions and generator expressions
  • I know when to choose comprehensions vs explicit loops