Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Doing the same thing many times

Open In Colab

Programs become powerful when they can repeat work automatically. Loops are the main tool for expressing repetition in Python.

This section focuses only on repetition, not on decisions. Every example does the same thing each time the loop runs.

1. The idea of a loop

One value at a time

A loop processes values one after another.

Instead of writing the same instruction many times, we describe a pattern:

Take one value, do something, move on to the next value.

This idea applies to many situations, such as:

  • printing all values in a list

  • performing the same calculation repeatedly

  • stepping through a sequence in order

The number of repetitions is controlled by the data, not by you.

Consider a simple list of values:

values = [3, 7, 12]

When a loop runs over this list, it does not see the list all at once. Instead, it works like this:

  • first, it sees 3

  • then, it sees 7

  • finally, it sees 12

At each step, the exact same instructions are executed again.


The loop variable

Each loop introduces a temporary variable.

This variable:

  • holds exactly one value at a time

  • changes automatically on each repetition

  • exists while the loop is running

The name of the loop variable is chosen by you and should be descriptive.


How loops run

Conceptually, a loop always follows the same steps:

  1. Take the next value from the sequence

  2. Assign it to the loop variable

  3. Execute the loop body

  4. Repeat until no values remain

Understanding this execution model is more important than memorising syntax.


2. The for loop

Iterating over collections

The most common loop in Python is the for loop. It is used to iterate over collections such as lists.

for item in collection:
    do_something(item)

This line tells Python to take one value from the collection at a time and run the same instructions for each value. Read it like a sentence:

For each item in the collection, do something with it.

The loop continues until the collection has no values left.


A concrete example

Consider a simple list of city names:

cities = ["Tokyo", "Delhi", "Shanghai", "Jakarta"]

Now run the following loop:

for city in cities:
    print(city)

What you will see as output:

Tokyo
Delhi
Shanghai
Jakarta

Python executes the same print(city) instruction four times. Each time, city refers to a different value from the list.

The code itself does not change. Only the value of city changes.


How Python executes this loop

Diagram showing a loop variable sequentially pointing to elements in a list one by one.

The loop variable acts as a temporary container. It holds the first value, executes the code, and then automatically moves to the next value until the list is empty.

Internally, Python proceeds step by step:

  1. Assigns "Tokyo" to city and runs the loop body

  2. Assigns "Delhi" to city and runs the loop body

  3. Assigns "Shanghai" to city and runs the loop body

  4. Assigns "Jakarta" to city and runs the loop body

  5. Stops because no values remain

At any moment, the loop variable holds exactly one value.


Loop body and indentation

Everything indented below the for statement belongs to the loop.

for city in cities:
    print(city)
    print("----")

Both print statements are part of the loop body, so both run once for each city.

When the indentation ends, the loop ends. Python does not use an explicit “end loop” keyword. Structure is defined entirely by indentation.


Loop variable lifetime

The loop variable is a normal variable. It is assigned a new value on each repetition.

After the loop finishes:

  • the variable still exists

  • it contains the last value from the collection

You can verify this directly:

print(city)
# Output: Jakarta

This behaviour can be surprising at first, so it is important to be aware of it.


3. Looping with range

Repeating a fixed number of times

Sometimes you do not want to loop over a list. You simply want to repeat an action a known number of times.

This is what range() is for.

for i in range(5):
    print(i)

When this code runs, you will see:

0
1
2
3
4

The loop runs five times. On each repetition, the loop variable takes on the next number in the sequence.


How range works

When range() is given a single number, it produces a sequence of integers:

range(5)  # Conceptually produces: 0, 1, 2, 3, 4

Important details:

  • the sequence always starts at 0 (unless specified otherwise)

  • the final value is not included (it stops before 5)

  • the length of the sequence matches the number you provide (5 numbers total)

This “start at zero, stop before the end” behaviour is the standard in Python.


Start, stop, step

The range() function can take one, two, or three arguments.

range(stop)
range(start, stop)
range(start, stop, step)

For example:

for i in range(2, 9, 3):
    print(i)

This produces:

2
5
8

Read this as:

Start at 2, increase by 3 each time, stop before reaching 9.

Using these arguments gives you precise control over how many repetitions occur.

You can learn a bit more about range by typing help(range).

help(range)

Typical use cases

Loops with range() are often used for:

  • counters

  • repeated actions

  • controlled sequences of numbers


4. Looping with index values

When values are not enough

So far, you have looped directly over the values in a list. In many cases, this is exactly what you want.

Sometimes, however, you also need to know where a value appears in a list. This is where index values become useful.

Accessing values by index

Recall that list elements are accessed using an index. The first element has index 0.

We can combine this idea with range() and len().

cities = ["Buenos Aires", "São Paulo", "Lima", "Bogotá", "Santiago"]

for i in range(len(cities)):
    print(f"{cities[i]} is at index {i}")

Output:

Buenos Aires is at index 0
São Paulo is at index 1
Lima is at index 2
Bogotá is at index 3
Santiago is at index 4

Here is what happens:

  • len(cities) gives the number of elements in the list (5)

  • range(5) produces the indices 0, 1, 2, 3, 4

  • i takes on each index value step-by-step

  • cities[i] accesses the corresponding city


Why the loop starts at zero

Because Python lists start at index 0, the first value in the list is accessed as cities[0].

Using range(len(cities)) ensures that:

  • every valid index is used

  • no index goes out of bounds

This pattern is common and worth recognising.


Index-based loops are especially useful when you have multiple lists that belong together.

cities = ["Buenos Aires", "Brasília", "Lima", "Bogotá", "Santiago"]
countries = ["Argentina", "Brazil", "Peru", "Colombia", "Chile"]

Each city corresponds to a country at the same index.

for i in range(len(cities)):
    print(cities[i], "is the capital of", countries[i])

Output:

Buenos Aires is the capital of Argentina
Brasília is the capital of Brazil
Lima is the capital of Peru
Bogotá is the capital of Colombia
Santiago is the capital of Chile

The index i allows access to matching elements from both lists at the exact same time.


When index-based loops are needed

Using indices is useful when:

  • you need to update values in a list

  • you want to refer to the position of an element

  • you need to access multiple related lists together

In many other cases, looping directly over values is simpler and clearer.



5. Nested loops

Repetition inside repetition

A loop can be placed inside another loop. This is called a nested loop.

for a in first_list:
    for b in second_list:
        print(a, b)

In this structure:

  • the outer loop controls the larger repetition

  • the inner loop runs fully from start to finish for each outer value


A concrete example

Consider two small lists:

colors = ["red", "blue"]
shapes = ["circle", "square"]

Now run the nested loop:

for color in colors:
    for shape in shapes:
        print(color, shape)

Observed output:

red circle
red square
blue circle
blue square

Each color is combined with every shape before the outer loop moves on to the next color.


Execution order

Nested loops always follow the same order:

  1. The outer loop takes its first value

  2. The inner loop runs through all its values

  3. The outer loop moves to the next value

  4. The inner loop runs again from the beginning

This creates a grid-like pattern of repetition.


Visualising the pattern

You can think of nested loops as filling a table or a spatial grid:

  • rows correspond to the outer loop

  • columns correspond to the inner loop

A 2D grid showing execution flow moving row by row, illustrating how an outer loop and inner loop interact.

The outer loop locks into a row, while the inner loop runs through all the columns. Once a row is finished, the outer loop moves down one step and the inner loop starts over.

Every cell represents one execution of the inner loop body. This is incredibly useful in spatial data science for working with coordinate pairs (x, y) or raster pixels!


6. Exercises

These exercises help you practise the core idea of repetition using loops.
Focus on understanding what happens, not on writing the shortest code.


Exercise 1: Looping over values

You are given a list of elevations (in meters):

elevations = [450, 1200, 890, 2300]
  1. Write a for loop that prints each elevation.

  2. Run the code and observe the output.

  3. How many times does the loop body execute?


Exercise 2: Repeating with range()

Write a loop that prints the numbers 1 to 5. Use range() to control the number of repetitions.

  1. Write the loop.

  2. Explain why the stop value is not printed.


Exercise 3: Looping with index values

You are given two related lists:

cities = ["Quito", "La Paz", "Asunción"]
countries = ["Ecuador", "Bolivia", "Paraguay"]
  1. Use an index-based loop to print each city together with its country.

  2. Why does looping directly over cities not work in this case?


Exercise 4: Nested loops and grids

You are given x and y coordinates:

x_coords = [3, 4, 5]
y_coords = [8, 9]
  1. Write a nested loop that prints all (x, y) coordinate pairs.

  2. How many times does the inner loop run in total?


Exercise 5: Predict before you run

Without running the code, predict the output:

values = [10, 20, 30]

for v in values:
    print(v)
print(v)
  1. What is printed by the loop?

  2. What is printed by the final print(v)?


7. Summary

In this section, you learned how Python expresses repetition using loops.

Key ideas

  • A loop processes values one at a time

  • The loop variable holds one value per iteration

  • for loops are used to iterate over collections

  • range() controls repetition when no list is involved

  • Index-based loops allow access to positions and related lists

  • Nested loops combine repetition across multiple dimensions


What comes next

So far, all loops have repeated the same action.

Next, we will introduce conditions, which allow loops to behave differently for different values. Repetition is about to become decision-aware.