Mastering iteration and thinking like a programmer
You've used while loops in your game loops, but there's a whole world of iteration patterns to explore. Today we'll master loops and use them to understand how algorithms work.
By the end of this lesson, you'll be able to write any kind of loop confidently and implement your first real algorithm.
Why this matters: Almost every program uses loops. Searching, sorting, processing data, game logic - it all depends on iteration. Understanding loops deeply is the foundation of algorithmic thinking.
Python has two main loop types. Each has its purpose:
| Loop Type | Use When... | Example Scenario |
|---|---|---|
while |
You don't know how many times to loop | Game loop until player quits, input validation |
for |
You know what you're iterating over | Process each item in a list, repeat N times |
# Keep asking until valid input
password = ""
while password != "secret123":
password = input("Enter password: ")
print("Access granted!")
# Game loop - runs until player decides to stop
playing = True
while playing:
action = input("What do you do? ")
if action == "quit":
playing = False
# Process each pet in a list
pets = ["Max", "Luna", "Buddy"]
for pet in pets:
print(f"Feeding {pet}...")
# Repeat exactly 5 times
for i in range(5):
print(f"Attempt {i + 1}")
# Go through each character in a string
word = "Python"
for letter in word:
print(letter)
For loop: "Do this for each item in this collection"
While loop: "Keep doing this while this condition is true"
Which loop type would you use for:
for - you know the itemswhile - unknown attempts neededfor - iterate over pet listThe for loop can iterate over any "iterable" - lists, strings, dictionaries, and more.
pets = ["Max", "Luna", "Buddy"]
# Basic iteration
for pet in pets:
print(pet)
# With index using enumerate()
for index, pet in enumerate(pets):
print(f"{index}: {pet}")
# Output:
# 0: Max
# 1: Luna
# 2: Buddy
# Starting enumerate at 1 (useful for display)
for position, pet in enumerate(pets, start=1):
print(f"Pet #{position}: {pet}")
# Output:
# Pet #1: Max
# Pet #2: Luna
# Pet #3: Buddy
word = "PYTHON"
# Each character
for char in word:
print(char)
# Count vowels in a word
vowels = "aeiouAEIOU"
count = 0
for char in word:
if char in vowels:
count += 1
print(f"Vowels found: {count}") # Output: 1
shop_items = {
'apple': 1.50,
'bread': 2.00,
'milk': 3.50
}
# Keys only (default)
for item in shop_items:
print(item) # apple, bread, milk
# Values only
for price in shop_items.values():
print(price) # 1.5, 2.0, 3.5
# Both keys and values
for item, price in shop_items.items():
print(f"{item}: ${price:.2f}")
# Output:
# apple: $1.50
# bread: $2.00
# milk: $3.50
range() generates a sequence of numbers. Essential for controlled iteration.
# range(stop) - 0 to stop-1
for i in range(5):
print(i) # 0, 1, 2, 3, 4
# range(start, stop) - start to stop-1
for i in range(1, 6):
print(i) # 1, 2, 3, 4, 5
# range(start, stop, step) - with custom step
for i in range(0, 10, 2):
print(i) # 0, 2, 4, 6, 8
# Counting backwards
for i in range(5, 0, -1):
print(i) # 5, 4, 3, 2, 1
print("Liftoff!")
range(5) gives you 0, 1, 2, 3, 4 - NOT 1, 2, 3, 4, 5!
If you want 1-5, use range(1, 6)
What would these print?
for i in range(3): print(i)for i in range(2, 5): print(i)for i in range(10, 0, -2): print(i)range(3): 0, 1, 2range(2, 5): 2, 3, 4range(10, 0, -2): 10, 8, 6, 4, 2Sometimes you need to exit a loop early or skip certain iterations. Python gives you three tools:
| Statement | What It Does |
|---|---|
break |
Exit the loop immediately |
continue |
Skip to the next iteration |
else |
Runs if loop completes without break |
# Find the first pet named "Luna"
pets = ["Max", "Luna", "Buddy", "Luna"]
for pet in pets:
if pet == "Luna":
print(f"Found {pet}!")
break # Stop searching, we found it
print(f"Checking {pet}...")
# Output:
# Checking Max...
# Found Luna!
# Without break, it would keep going and find both Lunas
# Feed all pets except the cat (she's picky)
pets = [
{"name": "Max", "species": "dog"},
{"name": "Whiskers", "species": "cat"},
{"name": "Buddy", "species": "dog"}
]
for pet in pets:
if pet["species"] == "cat":
print(f"Skipping {pet['name']} (cats feed themselves)")
continue # Skip to next pet
print(f"Feeding {pet['name']}...")
# Output:
# Feeding Max...
# Skipping Whiskers (cats feed themselves)
# Feeding Buddy...
# Search for an item - else runs if NOT found
shopping_list = ["apple", "bread", "milk"]
search_item = "eggs"
for item in shopping_list:
if item == search_item:
print(f"Found {search_item}!")
break
else:
# This runs ONLY if we didn't break
print(f"{search_item} not in list!")
# Output: eggs not in list!
# Now search for "bread"
search_item = "bread"
for item in shopping_list:
if item == search_item:
print(f"Found {search_item}!")
break
else:
print(f"{search_item} not in list!")
# Output: Found bread!
The else clause on loops is unique to Python. Think of it as "no break" - it runs when the loop completes normally without hitting a break.
In the Pet Simulator, where might you use:
break - to exit a loop early?continue - to skip certain items?break: Exit the game loop when user types "quit"break: Stop searching for a pet once foundcontinue: Skip feeding pets that aren't hungrycontinue: Skip sleeping pets when displaying statusThese patterns appear everywhere in programming. Master them and you can solve most problems.
# Count how many pets are hungry
pets = [
{"name": "Max", "hunger": 80},
{"name": "Luna", "hunger": 30},
{"name": "Buddy", "hunger": 75}
]
hungry_count = 0
for pet in pets:
if pet["hunger"] > 50:
hungry_count += 1
print(f"{hungry_count} pets are hungry") # 2 pets are hungry
# Calculate total price of cart
cart = [
{"item": "apple", "price": 1.50},
{"item": "bread", "price": 2.00},
{"item": "milk", "price": 3.50}
]
total = 0
for item in cart:
total += item["price"]
print(f"Total: ${total:.2f}") # Total: $7.00
# Python shortcut: sum() with generator
total = sum(item["price"] for item in cart)
# Find the first hungry pet
pets = [
{"name": "Max", "hunger": 30},
{"name": "Luna", "hunger": 80},
{"name": "Buddy", "hunger": 75}
]
hungry_pet = None
for pet in pets:
if pet["hunger"] > 50:
hungry_pet = pet
break # Found one, stop searching
if hungry_pet:
print(f"Feed {hungry_pet['name']} first!")
else:
print("No hungry pets!")
# Get ALL hungry pets
pets = [
{"name": "Max", "hunger": 30},
{"name": "Luna", "hunger": 80},
{"name": "Buddy", "hunger": 75}
]
hungry_pets = []
for pet in pets:
if pet["hunger"] > 50:
hungry_pets.append(pet)
print(f"Hungry pets: {[p['name'] for p in hungry_pets]}")
# Hungry pets: ['Luna', 'Buddy']
# Python shortcut: list comprehension
hungry_pets = [pet for pet in pets if pet["hunger"] > 50]
# Get just the names from pet objects
pets = [
{"name": "Max", "hunger": 30},
{"name": "Luna", "hunger": 80},
{"name": "Buddy", "hunger": 75}
]
pet_names = []
for pet in pets:
pet_names.append(pet["name"])
print(pet_names) # ['Max', 'Luna', 'Buddy']
# Python shortcut: list comprehension
pet_names = [pet["name"] for pet in pets]
An algorithm is a step-by-step procedure to solve a problem. It's like a recipe - specific instructions that always produce the same result.
Key insight: Algorithms are everywhere in programming. When you write a loop to search for something, you're implementing an algorithm!
The simplest search algorithm: check each item one by one until you find what you're looking for.
def linear_search(items, target):
"""
Search for target in items list.
Returns the index if found, -1 if not found.
"""
for index in range(len(items)):
if items[index] == target:
return index # Found it!
return -1 # Not found
# Test it
numbers = [4, 2, 7, 1, 9, 3]
result = linear_search(numbers, 7)
print(f"Found at index: {result}") # Found at index: 2
result = linear_search(numbers, 5)
print(f"Found at index: {result}") # Found at index: -1
def linear_search(items, target):
"""Search for target in items. Returns index or -1."""
for index, item in enumerate(items):
if item == target:
return index
return -1
# Even more Pythonic - using 'in' for existence check
def find_item(items, target):
"""Check if target exists and return it."""
for item in items:
if item == target:
return item
return None
In real programs, you often search through objects, not just simple values.
def find_pet_by_name(pets, name):
"""Find a pet by name. Returns the pet or None."""
for pet in pets:
if pet["name"].lower() == name.lower():
return pet
return None
def find_hungry_pets(pets, hunger_threshold=50):
"""Find all pets above hunger threshold."""
hungry = []
for pet in pets:
if pet["hunger"] > hunger_threshold:
hungry.append(pet)
return hungry
# Usage
pets = [
{"name": "Max", "species": "dog", "hunger": 30},
{"name": "Luna", "species": "cat", "hunger": 80},
{"name": "Buddy", "species": "dog", "hunger": 75}
]
pet = find_pet_by_name(pets, "luna")
if pet:
print(f"Found {pet['name']} the {pet['species']}")
else:
print("Pet not found")
hungry = find_hungry_pets(pets)
print(f"Hungry pets: {[p['name'] for p in hungry]}")
How fast is linear search? It depends on where the item is:
| Scenario | Comparisons Needed | Example (100 items) |
|---|---|---|
| Best case (first item) | 1 | 1 comparison |
| Worst case (last or not found) | N (all items) | 100 comparisons |
| Average case | N/2 | 50 comparisons |
Linear search works fine for small lists. But imagine searching through 1 million items - worst case means 1 million comparisons!
In future lessons, we'll learn Binary Search, which can search 1 million sorted items in just 20 comparisons.
Let's add search functionality to the PetShop class from your homework.
class PetShop:
"""Manages multiple pets with search capabilities."""
def __init__(self):
self.pets = []
def add_pet(self, pet):
"""Add a pet to the shop."""
self.pets.append(pet)
# --- SEARCH METHODS ---
def find_by_name(self, name):
"""Linear search for a pet by name."""
for pet in self.pets:
if pet.name.lower() == name.lower():
return pet
return None
def find_by_species(self, species):
"""Find ALL pets of a species."""
matches = []
for pet in self.pets:
if pet.species.lower() == species.lower():
matches.append(pet)
return matches
def find_hungry_pets(self, threshold=50):
"""Find all pets with hunger above threshold."""
hungry = []
for pet in self.pets:
if pet.hunger > threshold:
hungry.append(pet)
return hungry
def count_by_species(self):
"""Count how many of each species."""
counts = {}
for pet in self.pets:
species = pet.species
if species in counts:
counts[species] += 1
else:
counts[species] = 1
return counts
# --- DISPLAY METHODS ---
def show_all(self):
"""Display all pets."""
if not self.pets:
print("No pets in shop!")
return
print(f"\n--- Pet Shop ({len(self.pets)} pets) ---")
for i, pet in enumerate(self.pets, start=1):
print(f"{i}. {pet.name} ({pet.species})")
# Usage example
shop = PetShop()
shop.add_pet(Pet("Max", "dog"))
shop.add_pet(Pet("Luna", "cat"))
shop.add_pet(Pet("Buddy", "dog"))
shop.add_pet(Pet("Nemo", "fish"))
# Find a specific pet
pet = shop.find_by_name("luna")
if pet:
pet.status()
# Find all dogs
dogs = shop.find_by_species("dog")
print(f"Dogs: {[p.name for p in dogs]}") # ['Max', 'Buddy']
# Count species
print(shop.count_by_species()) # {'dog': 2, 'cat': 1, 'fish': 1}
| Type | When to Use | Syntax |
|---|---|---|
for |
Known collection or count | for item in collection: |
while |
Unknown iterations | while condition: |
| Statement | Effect |
|---|---|
break |
Exit loop immediately |
continue |
Skip to next iteration |
else |
Runs if no break occurred |
for loops with lists, strings, dicts, and range()break and continuePractice loops and algorithms with challenges that build on the Pet Simulator. This homework reinforces everything we covered today.
Click here to download the homework file
Remember: Focus on understanding the patterns. Once you recognize them, you can apply them anywhere!
Next lesson: We'll explore more algorithms - sorting algorithms (how to arrange items in order) and binary search (searching sorted data much faster than linear search).