While loops#

For loops are a very valuable construct for repeating something when you already know how many times you will need to repeat (even if that is determined by some other variable). However, we often wish to repeat until a condition is no longer satisfied. For example, we might summarise the process of debugging as “while there are still bugs in the program, fix a bug!”

Python offers the while loop for this purpose. It has the following form:

while <condition>:
    things to do while the condition is True

Python will first evaluate the condition. If it is True, then the loop body will be run. The condition will then be checked again, and if it is True the loop body will be run again. This continues until the condition evaluates to False. Here’s an example:

x = 0.9
i = 0

while x != 0.5:
    x = 2*x*(1-x)
    i += 1  # increment i manually, as we're not using a for-loop
    print(f"after {i} iterations, x = {x}")
after 1 iterations, x = 0.17999999999999997
after 2 iterations, x = 0.29519999999999996
after 3 iterations, x = 0.41611392
after 4 iterations, x = 0.4859262511644672
after 5 iterations, x = 0.49960385918742867
after 6 iterations, x = 0.49999968614491325
after 7 iterations, x = 0.49999999999980305
after 8 iterations, x = 0.5

Note that the condition isn’t checked inside the loop body, so Python won’t break the loop halfway through the loop body if the condition becomes False. Because of this, if we rearranged the statements in the loop body, we would get a different final number printed:

x = 0.9
i = 0

while x != 0.5:
    print(f"after {i} iterations, x = {x}")
    i += 1
    x = 2*x*(1-x)
after 0 iterations, x = 0.9
after 1 iterations, x = 0.17999999999999997
after 2 iterations, x = 0.29519999999999996
after 3 iterations, x = 0.41611392
after 4 iterations, x = 0.4859262511644672
after 5 iterations, x = 0.49960385918742867
after 6 iterations, x = 0.49999968614491325
after 7 iterations, x = 0.49999999999980305

In the example below, we have a turtle draw a spiral from the centre until it reaches a bounding box 150 units away from the centre.

from mobilechelonian import Turtle
import numpy as np

# the centre coordinate is (200, 200)
centre = 200

# create a turtle caled Terry
terry = Turtle()
terry.speed(10)

# we need a variable to keep track of the angle to turn to make the spiral
i = 1

# Loop until terry is 150 away from the centre in the x or y direction.
# np.abs computes the absolute value of its argument, so we are testing the if the difference
# between centre and posX is < 150, and the difference between centre and posY is < 150.
while (np.abs(centre - terry.posX) < 150) and (np.abs(centre - terry.posY) < 150):
    # move forward a small amount to approximate a curve
    terry.forward(5)
    
    # The angle terry turns should get smaller as he goes to obtain a spiral
    # so turn by 360/i, then increase i.
    # There are many other choices that would also make a spiral.
    terry.left(360/i)
    i = i + 1

Infinite loops#

There is a danger lurking in while loops: what happens if the condition never becomes False? Python will simply keep running the loop body forever. This is called an infinite loop, and is one of the common causes of programs freezing or crashing. Whenever you write a while loop, you should consider how you know it will eventually finish, i.e. how you know that the condition will eventually be false. It is literally impossible for Python to decide whether a general while loop will terminate, and so it is up to you as the programmer! Proving that a while loop will terminate often requires some mathematical insight.

If you run into an infinite loop (or simply a loop which is taking too long to terminate), you can stop Python executing your code by clicking the “stop” button in the menu beside the “Run” button.

Breaking out of loops#

There are two common alternatives used to break out of while loops. The first is the break statement. When this is encountered in a loop, Python will immediately stop executing the loop and go to the next line in the code. If you have nested loops, break will only break out of the inner-most loop that contains the break statement.

In the example below, a break statement is used to exit a while loop when the user inputs the correct number. We’ll discuss user input more in the final worksheet. If you execute the following cell, Python will get “stuck” in the loop and you will have to exit using the “stop” button in the menu bar, or by guessing the correct number. The technique used in this example - using while True to keep looping and processing user input - is called an “event loop” and lies at the heart of any program you can interact with continuously, like office software or games.

import random
# This program implements a guessing game where numbers are
# read in from the user in order to guess an answer known to the
# computer

# First set the answer to be a random number between 0 and 100
answer = random.randint(0, 100)

# Explain in words what the user needs to do:
print("Guess a number between 0 and 100 - I only stop when you get it right!")

# Start a while loop which only exits if the user guesses the number correctly
while True:
    # This line reads in a guess from the user:
    guess = int(input(">"))
    # Next see whether the guess is too small, too large or right:
    if guess < answer:
        print("Higher")
    elif guess > answer:
        print("Lower")
    else:
        # If we get here the answer is right
        print("Correct! Congratulations.")
        # If the answer is right exit the loop
        break
print("Come back and play again soon!")
Guess a number between 0 and 100 - I only stop when you get it right!
---------------------------------------------------------------------------
StdinNotImplementedError                  Traceback (most recent call last)
Input In [4], in <cell line: 13>()
     12 # Start a while loop which only exits if the user guesses the number correctly
     13 while True:
     14     # This line reads in a guess from the user:
---> 15     guess = int(input(">"))
     16     # Next see whether the guess is too small, too large or right:
     17     if guess < answer:

File ~/opt/anaconda3/envs/jupyterbook/lib/python3.10/site-packages/ipykernel/kernelbase.py:1174, in Kernel.raw_input(self, prompt)
   1167 """Forward raw_input to frontends
   1168 
   1169 Raises
   1170 ------
   1171 StdinNotImplementedError if active frontend doesn't support stdin.
   1172 """
   1173 if not self._allow_stdin:
-> 1174     raise StdinNotImplementedError(
   1175         "raw_input was called, but this frontend does not support input requests."
   1176     )
   1177 return self._input_request(
   1178     str(prompt),
   1179     self._parent_ident["shell"],
   1180     self.get_parent("shell"),
   1181     password=False,
   1182 )

StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.

Break statements can also be used in for loops. They are often used when you are searching for an object with some property, and there is no reason to keep doing work once you have found it.

# Sets i to be the first integer between 100 and 200 which is divisible by 47.
# There are better ways of doing this!

for i in range(100, 201):
    if i % 47 == 0:
        # if we break now, the variable i will keep its current value
        break

print(f"the first multiple of 47 between 100 and 200 is {i}")
the first multiple of 47 between 100 and 200 is 141

The other standard way of breaking loops applies if the loop is contained in a function. Since a return statement immediately stops the function from being run and returns the control flow to where it was called from, it also breaks out of any loop in the function.