Nested for loops#

It is often useful to “nest” a loop inside another loop. When this occurs, the “inner” loop (i.e. the one inside the body of the other loop) will be fully executed, then the “outer” loop will iterate; the inner loop will execute again, and so on until the outer loop is finished.

This idea is easiest seen by example. Note that the body of the inner loop is indented two levels.

for i in range(2):
    print("Start of the outer loop body")
    for j in range(3, 5):
        print(f"  Inner loop: the outer loop variable is {i} and inner loop variable is {j}")
    print("End of the outer loop body")
Start of the outer loop body
  Inner loop: the outer loop variable is 0 and inner loop variable is 3
  Inner loop: the outer loop variable is 0 and inner loop variable is 4
End of the outer loop body
Start of the outer loop body
  Inner loop: the outer loop variable is 1 and inner loop variable is 3
  Inner loop: the outer loop variable is 1 and inner loop variable is 4
End of the outer loop body

This might seem like a strange thing to want to do, but many problems involve repeating a repetitive task. For example, suppose you have an inbox full of emails you need to respond to. You could represent the basic process of responding to all your emails like this:

  • For each email in your inbox:

    • For each word in the email:

      • Read the word

    • Think of a response

    • For each word of the response:

      • Write the word

      • Add any necessary punctuation

We could also break down writing words into repeatedly typing letters - another level of nesting in our repetition! You can nest loops as much as you want in Python, but if you find yourself with many levels of nesting it is usually a sign that you need to reconsider what you are doing and try to simplify it.

Here’s another example, where we output some short multiplication tables.

for i in range(7, 10):
    print(f"{i} times table:")
    for j in range(1, 5):
        print(f"{i} x {j} is {i*j}")
    print() # print a blank line; note that this is only in the "outer" loop
7 times table:
7 x 1 is 7
7 x 2 is 14
7 x 3 is 21
7 x 4 is 28

8 times table:
8 x 1 is 8
8 x 2 is 16
8 x 3 is 24
8 x 4 is 32

9 times table:
9 x 1 is 9
9 x 2 is 18
9 x 3 is 27
9 x 4 is 36

Here’s an example with a turtle; we draw a triangle with a small hexagon attached to each corner.

from mobilechelonian import Turtle

leo = Turtle()
leo.speed(8)

# loop 3 times for the triangle
for i in range(3):
    leo.forward(100)
    # get the hexagon in the right orientation
    leo.right(90)

    # loop 6 times for the hexagon
    for i in range(6):
        leo.forward(30)
        leo.left(60)

    # point the turtle back in the right direction for the next triangle edge
    leo.left(210)

Finally, let’s use nested loops to compute the double sum $\( \sum_{i = 1}^{10} \sum_{j = 2 \text{, j even}}^{20} \frac{1}{i ^2 j}. \)$

# start with the total being 0
total = 0

# Use nested for-loops for the double sum.
# The loop variables correspond to the sum indices.
for i in range(1, 11):
    for j in range(2, 21, 2):
        term = 1 / (i**2 * j)
        # the next line means "total = total + term"
        total += term
total
2.2696102428056033