Python Loops: for, while, and Loop Control
Loops let you repeat code without copying and pasting it. Whether you're watering every plot on a farm grid, processing a list of crops, or running a simulation until a condition is met, loops are the tool for the job. Python provides two main loop types β for and while β plus a set of control keywords that give you precise command over how those loops run.
The for Loop
A for loop iterates over the items in any iterable β a list, string, range, tuple, or dictionary. Python automatically moves to the next item on each pass.
crops = ["wheat", "carrot", "tomato", "pumpkin"]
for crop in crops:
print(f"Checking {crop}...")
# Output:
# Checking wheat...
# Checking carrot...
# Checking tomato...
# Checking pumpkin...
The loop variable (crop) takes each value in sequence. You can name it whatever makes sense for your context.
range()
range() generates a sequence of integers and is the most common companion to for loops. It takes up to three arguments: start, stop, and step.
# range(stop) β starts at 0, stops before stop
for i in range(5):
print(i) # 0 1 2 3 4
# range(start, stop)
for i in range(2, 6):
print(i) # 2 3 4 5
# range(start, stop, step)
for day in range(0, 28, 7):
print(f"Week {day // 7 + 1} of the season")
# Countdown with negative step
for i in range(10, 0, -1):
print(i, end=" ") # 10 9 8 7 6 5 4 3 2 1
The while Loop
A while loop keeps running as long as its condition is True. Use it when you don't know the number of iterations in advance.
gold = 10
seed_cost = 7
while gold >= seed_cost:
gold -= seed_cost
print(f"Bought seed. Gold left: {gold}")
print(f"Can't afford more seeds. Remaining gold: {gold}")
# Bought seed. Gold left: 3
# Can't afford more seeds. Remaining gold: 3
False, the loop runs forever and crashes your program. Always make sure the loop variable changes inside the body.
break and continue
break exits the loop immediately, regardless of the condition. continue skips the rest of the current iteration and jumps to the next one.
plots = [
{"name": "wheat", "mature": False},
{"name": "carrot", "mature": True},
{"name": "tomato", "mature": False},
{"name": "pumpkin","mature": True},
]
# continue β skip plots that aren't ready
for plot in plots:
if not plot["mature"]:
continue
print(f"Harvesting {plot['name']}!")
# break β stop at the first mature crop
for plot in plots:
if plot["mature"]:
print(f"Found ready crop: {plot['name']}")
break
Loop else Clause
Python's loops have an optional else block that runs only when the loop completes naturally β meaning it was not exited via break. It's useful for "search and not found" patterns.
target = "pumpkin"
for plot in plots:
if plot["name"] == target and plot["mature"]:
print(f"{target} is ready to harvest!")
break
else:
print(f"No ready {target} found on the farm.")
Nested Loops: 2D Grid Example
Two nested for loops let you walk every cell in a 2D grid β exactly what you need for a farming game map.
ROWS = 4
COLS = 4
# Build a 4x4 grid of None (empty plots)
grid = [[None] * COLS for _ in range(ROWS)]
# Plant wheat in every cell
for row in range(ROWS):
for col in range(COLS):
grid[row][col] = {"name": "wheat", "days": 0}
# Print grid coordinates
for row in range(ROWS):
for col in range(COLS):
cell = grid[row][col]
label = cell["name"] if cell else "."
print(label, end=" ")
print() # newline after each row
enumerate() and zip()
enumerate() gives you both the index and the value during iteration. zip() pairs up two iterables so you can walk them together.
crops = ["wheat", "carrot", "tomato"]
yields = [25, 15, 40]
# enumerate: i is the index, crop is the value
for i, crop in enumerate(crops):
print(f"Slot {i}: {crop}")
# zip: pair crops with their yields
for crop, value in zip(crops, yields):
print(f"{crop} sells for {value} gold")
List Comprehensions
A list comprehension is a concise one-liner that builds a new list by looping over an iterable. It's often cleaner than a full for loop when the sole purpose is to produce a list.
values = [10, 25, 15, 40, 30]
# Regular loop
doubled = []
for v in values:
doubled.append(v * 2)
# Equivalent list comprehension
doubled = [v * 2 for v in values]
# With a filter β only mature crops
plots = [
{"name": "wheat", "mature": True, "value": 25},
{"name": "carrot", "mature": False, "value": 15},
{"name": "tomato", "mature": True, "value": 40},
]
ready = [p["name"] for p in plots if p["mature"]]
print(ready) # ['wheat', 'tomato']
Practical: Watering Every Plot
Here's a complete function that uses a nested for loop to water every cell in a 2D farm grid, skipping empty plots and tracking total water used:
def water_all_plots(grid, water_per_plot=1.0):
"""Water every occupied plot. Returns total water used."""
total_used = 0.0
rows = len(grid)
cols = len(grid[0]) if rows > 0 else 0
for i in range(rows):
for j in range(cols):
cell = grid[i][j]
if cell is None:
continue # skip empty plots
cell["water"] = min(1.0, cell.get("water", 0) + water_per_plot)
total_used += water_per_plot
print(f" Watered ({i},{j}) β {cell['name']}")
print(f"Total water used: {total_used}L")
return total_used