How to use while loops in Python
The Python while loop can be used to execute a block of code for as long as a certain condition is fulfilled. While loops are primarily used in Python when the number of iterations can’t be determined at the time of writing the code. Keep reading to find out how the Python while loop works.
Teach yourself how to program in Python with our Python tutorial.
What is the while loop in Python?
The Python while loop is a control structure. Control structures determine which path of code will be followed at runtime. In general, loops are used to repeatedly execute a block of code. Here’s an overview of the most important control structures in Python:
Control structures in Python | Explanation |
---|---|
If-else statements | Executes a block of code once, if a condition is fulfilled |
While loops | Executes a block of code repeatedly, as a long as a condition is true |
For loops | Iterates over elements in a collection and executes the block of code for each element |
Beginner programmers often try to mimic the functionality of loops without knowing how they work. Rather than defining a data structure with several elements and processing it with a loop, they define a separate variable for each data set. They also duplicate the code for processing the data sets. The result is suboptimal code. This is illustrated in the code below:
person1 = ('Anne', 17)
person2 = ('Marie', 42)
person3 = ('Kate', 63)
print(f"{person1[0]}, {person1[1]} years old")
print(f"{person2[0]}, {person2[1]} years old")
print(f"{person3[0]}, {person3[1]} years old")
In addition to the duplicate code, this approach also has a logistical problem: If the number of data sets can’t be defined until runtime, the individual variables can’t be defined in advance. This is where loops and collections of elements come in.
If it is known how many repetitions will be needed at runtime, a Python for loop will be the best option. For example, we can reformulate the code from above using a for loop. It will then work without any duplicate code and only uses two variables, regardless of the number of data sets involved.
people = ('Jim', 'Jack', 'John')
ages = (17, 42, 63)
for person, age in zip(people, ages):
print(f"{person}, {age} years old")
On the other hand, you’ll want to use a while loop in Python when you don’t know in advance how many times the code will need to be repeated. For example, say you want to write code for the exchange of messages over an open connection. As long as the connection is up, messages will be processed. A Python if statement in the body of the loop will evaluate signals and potentially terminate the connection, if called for:
while connection_open():
print('Ready to receive')
process_messages()
if should_close_connection():
close_connection()
# once loop terminates
print('Connection was closed')
Python while loops are also used for unlimited iterations. Some well-known examples are ATMs, the Linux command prompt and the Python Read-Eval-Print loop (REPL). Below we show a sketch of an REPL implementation using an infinite while loop.
# Loop
while True:
# Read user input
user_input = read_input()
# Evaluate input and produce result
result = eval(user_input)
# Print result
print(result)
How does the Python while loop work?
The Python while loop works much like if statements in Python. Both of these control structures have two parts:
- A condition that will be evaluated
- A body with instructions
The difference between them is how many times the body is executed. The body of an if statement is executed one time, at most:
if condition:
run_once()
In contrast, the body of a while loop can be executed several times:
while condition:
run_again()
A Python while loop will run as follows:
- The condition is evaluated.
- If the condition is true, the body of the loop is executed.
- The condition is evaluated again.
- If the condition is still true, the process is repeated.
- If the condition is false, the loop is terminated.
Similar to if statements, the while loop in Python can also include an else block. The else block is optional and will be executed once if the condition is (or becomes) false.
while False:
# this code doesn't loop
never_runs()
else:
# instead, this code runs once
runs_once()
What’s the difference between for loops and while loops in Python?
The Python while loop is related to the for loop. Both of them are used to repeatedly execute a block of code. (This is also called 'iterating'.) The difference is how many times the code is executed.
In Python, for loops are primarily used to iterate over the elements in a collection. The maximum number of iterations is limited by the length of the collection. Below we iterate over the letters in the word 'Python' and output each letter:
for letter in 'Python':
print(letter)
The Python while loop isn’t based solely on iterating over collections. It has a number of flexible uses. The while loop is the more basic loop construct. Whereas a for loop can be constructed using a while loop, a while loop cannot be constructed using a for loop.
Let’s look at a few examples. Below we’ll use a while loop to recreate the functionality of a typical for loop with a numerical loop variable. To do this, we’ll define a counter variable outside the loop and increment its value within the loop.
counter = 0
limit = 10
while counter < limit:
print(counter)
counter += 1
The equivalent for loop is shorter and more direct:
for counter in range(10):
print(counter)
Now let’s use a while loop to iterate over the letters in a word. The results will be similar to the above example. We’ll use an iterator and the next() function. If the iterator is exhausted, None will be returned instead of a letter and the loop will be terminated. The resulting code is much more complicated than the equivalent for loop. A while loop is clearly not the best solution for this problem:
word = 'Python'
letters = iter(word)
letter = ''
while letter is not None:
letter = next(letters, None)
if letter:
print(letter)
Be careful with infinite while loops in Python
Python while loops are especially interesting because they can be used to implement infinite loops. At first glance this might seem counterintuitive, as programmers fear accidental infinite loops. That’s because the condition never becomes false, so the program gets stuck:
while True:
print("Forever…")
Accidental infinite loops are usually the result of an expression that always evaluates to True. For example:
while 1 == 1 + 1 - 1:
print("And ever…")
There are, however, a number of uses for intentionally created infinite loops.
If you find yourself stuck in an infinite while loop in Python REPL, the keyboard shortcut Ctrl + C can help. It will send a stop signal to the Python interpreter, which will then terminate execution of the loop.
Breaking and skipping while loops in Python
A while loop will usually iterate until the loop condition becomes false. A common but problematic trick is to use a flag variable as the condition. This involves defining a Boolean variable outside of the loop and evaluating it in the loop condition. When a certain condition has been reached in the body of the loop, we change the flag variable. When the condition is evaluated in the next iteration, the new value will cause the loop to terminate.
aborted = False
while not aborted:
print("Still going…")
if some_cond:
# will prevent next iteration
aborted = True
This solution is commonly used but isn’t particularly elegant. What happens when there’s more code in the body of the loop after the flag variable has been changed? The code has to be skipped. Luckily there’s a break statement for while loops in Python.
If a break statement is executed within a loop, the loop will be terminated immediately. Perhaps you can see the similarity between break statements in loops and return statements in functions. One difference is, however, that break statements don’t return a value. It’s common practice to use a break statement to terminate an infinite loop.
while True:
print("Still going…")
if some_cond:
break
# we never get here
print("We shouldn't be here")
# we end up here after breaking
print("Done.")
A close relative of break statements are continue statements. If a continue statement is executed in the body of the loop, the code following it will be skipped. Execution will continue with the next iteration. Break and continue statements can be used to implement simple, text-based menus, like those from early computer games:
# 'continue' takes us here
while True:
print("Press G to start a new game")
print("Press S to see stats")
print("Press M for main menu")
print("Press Q to quit")
key_press = input("Your choice \n")[0].upper()
print(f"You pressed {key_press}")
if key_press == "G":
# start game routines
print("Starting game …")
elif key_press == "S":
# show stats
print("Showing stats …")
elif key_press == "M":
# back to main menu
print("Returning to menu")
continue
elif key_press == "Q":
# break out of loop
print("Quitting")
break
else:
print("Unknown command. Try again")
# "break" takes us here
...
How to use while loops in Python
There are a number of diverse uses for while loops in Python. While loops are generally used for algorithms where the number of iterations can’t be defined in advance or where that number changes during execution. While loops are often used in combination with other control structures like decision-making statements and try-else statements. Let’s look at a few examples.
Consuming a collection with while loops in Python
For loops are a good option for iterating over the elements in a collection in Python. At least, this is the case as long as the collection isn’t changed in the body of the loop. But what happens if we make changes as we go through the elements? Imagine we want to remove elements from the collection while iterating. This is referred to as 'consuming' a collection.
Strange errors can arise when the underlying collection in a for loop is changed during iteration. If we want to consume a collection, a while loop is the better choice in Python. We’ll make the collection the condition of the while loop. As long as the collection still contains elements, it will be evaluated to True in a Boolean context. If the collection is empty, it will evaluate to False and the loop will terminate.
pieces = ['x', 'o', 'o', 'o', 'x', 'o', 'x', 'x']
while pieces:
piece = pieces.pop()
print(f"Removed {piece}")
# test
assert pieces == []
Implementing your own range() function with while loops in Python
While loops can also be used to implement generators in Python. A generator is a function that uses a yield statement and generates values on command. Below we’ll create our own implementation of the range() function. We’ll use the yield statement in a while loop to generate continuous numbers. When we reach the yield statement, a value will be returned and the loop will pause.
def my_range(start, stop):
# only positive ranges implemented
if stop <= start:
return None
current = start
while current < stop:
yield current
# next call of next() continues here
current += 1
# test
assert list(my_range(7, 9)) == list(range(7, 9))
Optimising a model using the Python while loop
Optimising models is part of standard practice in academic disciplines. It involves calculating a model based on a set of parameters. Afterwards, the parameters are adjusted and the model is calculated again. An objective function is used to estimate whether changing the parameters resulted in a better model. If so, the process is repeated. This is how iteration can be used to find optimal parameters for the model.
Normally the model levels off after a number of iterations, meaning that improvement between models will get smaller and smaller. If improvement falls below a certain value, we’ll terminate optimisation. To make sure that the loop is terminated, we’ll set a limit for the maximum number of iterations. The following shows this approach for optimising models using a while loop in Python.
limit = 5
round = 0
progress = True
while progress and round < limit:
# attempt next optimization
round += 1
# compute optimized parameters
params = optimize(params)
# make a copy of the old model
old_model = model
# compute new model using optimized parameters
model = run(model, params)
# worthwhile to continue optimizing?
progress = has_improved(model, old_model)
Establishing connections with the while loop and implementing try-except
Establishing a connection doesn’t always work on the first try, which is why multiple attempts are often used. Since we can’t know in advance how many tries will be necessary, we’ll use a while loop. We’ll set a limit on the maximum number of attempts and abort with an error message if none of the attempts were successful.
Here’s the approach we’ll take in Python. We use a try-except statement to catch errors in establishing a connection. The use of a break statement in the try block and a continue statement in the except block will ensure that we iterate correctly. If the connection isn’t established, we’ll try again with continue. If the connection is established, we terminate the loop using break.
max_tries = 10
attempt = 0
conn = None
# 'continue' takes us here
while attempt < max_tries:
attempt += 1
print("Trying to get a connection")
try:
# might raise 'ConnectionException'
conn = get_connection()
# got our connection
break
# "get_connection()" raised 'ConnectionException'
except ConnectionException:
print("Something went wrong. Trying again")
continue
# went through 'max_tries' unsuccessful connection attempts
else:
assert conn is None
print("Unable to connect")
# 'break' takes us here
assert conn is not None
print("Connection established")
Iterating over recursive structures with the Python while loop
The while loop in Python is well suited to solving recursive problems. This means that it’s a good option for iterating over:
- Embedded lists
- Tree structures
- Graphs
Let’s look at how that works using the example of Russian nesting dolls. The toy consists of wooden dolls that nest inside of each other. From the outside, it’s impossible to know how many dolls are inside, so we’ll take an iterative approach. We’ll open the first doll and see what we find inside. If there’s another doll, we repeat the process. This is a typical use case for while loops.
We can model the dolls as embedded lists that each contain a single element. The lists will either contain another list or an object that’s not a list. We’ll literate over a doll as long as it’s a list. In the body of the loop, we’ll use an assignment to go one level deeper. At some point we’ll find an element that’s not a list. At that point the iteration will terminate.
def open_doll(doll):
"""
* Dolls dolls stacked five levels deep, with 'None' inside:
'doll = [[[[[None]]]]]'
"""
while type(doll) is list:
print("Opening the next doll")
# go one level deeper
doll = doll.pop()
else:
print(f"Reached the bottom and found {doll}")
return doll
# test
doll = [[[[[None]]]]]
assert open_doll(doll) is None
This simple approach works regardless of how deeply embedded the doll is. Our algorithm will dig to the bottom and reveal the embedded object. That’s the magic of Python while loops in action.
Running a Python while loop on a game board
Another frequent use for Python while loops is moving pieces in boardgames. If you want to make sure to cover all fields, you’ll need two loops embedded in each other. But be sure to pay attention to the runtime. Under certain circumstances the program can run for a very long time.
We implement a simple 'random walk' in which the character moves randomly until it arrives at a destination. This kind of movement pattern is similar to the movement of a particle in liquid or a fly flying around a room. Since it’s not known in advance how many iterations will be needed, this is a job for the while loop.
First we’ll define the function random_walk(), which will contain the while loop. With the Python operator for 'equal to', we’ll check whether the character’s current location is its destination. If not, we iterate again.
def random_walk(board = (10, 10), goal = (4, 4), start = (0, 0)):
# ensure arguments are valid
if not (goal[0] in range(board[0]) and goal[1] in range(board[1]) and start[0] in range(board[0]) and start[1] in range(board[1])):
print(f"Goal {goal} and / or start position {start} outside of board with dimensions {board}")
return None, 0
steps = 0
pos = start
# as long as we haven't reached the goal
while not pos == goal:
# move to neighboring position
pos = get_neighbor(pos, board)
steps += 1
print(f"Moved to position {pos}")
print(f"Reached goal at {pos} after {steps} steps")
return pos, steps
We’ll also define a helper function get_neighbor(), which will return the field around a certain location.
def get_neighbor(pos, bounds):
from random import choice
"""
x = 0 . . . m
- - - - - - - -
y = 0 |
|
. | (x, y-1)
. | (x-1, y) (x, y) (x+1, y)
. | (x, y+1)
|
n |
"""
x, y = pos
# computer neighbors
neighbors = [ (x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1) ]
# filter out neighbors that are outside of bounds
neighbors = [ pos for pos in neighbors if 0 <= pos[0] < bounds[0] and 0 <= pos[1] < bounds[1] ]
# select a random neighbor
neighbor = choice(neighbors)
return neighbor
Finally, we’ll test our random walk implementation.
random_walk(board = (10, 10), goal = (4, 4), start = (5, 7))