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.

python
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.

python
# 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.

python
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
Infinite loop warning: If the condition never becomes 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.

python
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.

python
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.

python
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.

python
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.

python
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:

python
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