7 Loops

When the same operation has to be repeated several times, for a given number of times or as long as a condition is verified (or as long as it is not verified), loops can be used, which is much less painful than evaluating by hand or by copying and pasting the same instruction.

We will discuss two types of loops in this chapter:

  • those for which we do not know a priori the number of iterations (the number of repetitions) to be performed: while() loops
  • those for which we know a priori how many iterations are necessary: for() loops

It is possible to stop a for() loop before a predefined number of iterations; in the same way, it is possible to use a while() loop by knowing in advance how many iterations to perform.

7.1 Loops with while()

The principle of a while() loop is that instructions inside the loop will be repeated as long as a condition is met. The idea is to make this condition depend on one or more objects that will be modified during the iterations (otherwise, the loop would turn infinitely).

The syntax is as follows:

while condition:
  instructions

As for conditional instructions (see Section 6), the instructions are placed inside a block.

Let’s look at an example of a while() loop:

x = 100
while x/3 > 1:
  print(x/3)
  x = x/3
## 33.333333333333336
## 11.111111111111112
## 3.703703703703704
## 1.234567901234568
print(x/3>1)
## False
print(x/3)
## 0.41152263374485604

In this loop, at each iteration, the value of x divided by 3 is displayed, then the value of x is replaced by a third of its current value. This operation is repeated as long as the expression x/3 > 1 returns True.

7.2 Loops with for()

When we know the number of iterations in advance, we can use a for() loop. The syntax is as follows:

for object in possible_values:
  instructions

with object the name of a local variable at the function for(), possible_values an object comprising \(n\) elements defining the values that object will take for each of the \(n\) turns, and instructions the instructions that will be executed at each iteration.

In the following example, we will calculate the square of the first \(n\) integers. The values that our object variable (which we will call i) will take will be integers from 1 to \(n\). To obtain a sequence of integers in Python, we can use the range() function, which takes the following arguments:

  • start : (optional, default, 0) start value for the sequence (included) ;
  • stop : end value of the sequence (not included) ;
  • step : (optional, default 1) the step.

Before calculating the sequence of the \(n\) first squares, let’s look at an example of how the range() function works:

print(list(range(0, 4))) # Les entiers de 0 à 3
## [0, 1, 2, 3]
print(list(range(4))) # Les entiers de 0 à 3
## [0, 1, 2, 3]
print(list(range(2, 10))) # Les entiers de 2 à 9
## [2, 3, 4, 5, 6, 7, 8, 9]
print(list(range(2, 10, 3))) # Les entiers de 2 à 9 par pas de 3
## [2, 5, 8]

To display the sequence of the first \(10\) first squares, we can write:

message = "The squared value of {} is {}"
n=10
for i in range(0, n+1):
  print(message.format(i,i**2))
## The squared value of 0 is 0
## The squared value of 1 is 1
## The squared value of 2 is 4
## The squared value of 3 is 9
## The squared value of 4 is 16
## The squared value of 5 is 25
## The squared value of 6 is 36
## The squared value of 7 is 49
## The squared value of 8 is 64
## The squared value of 9 is 81
## The squared value of 10 is 100

During the first iteration, i is 0. In the second case, i is 1. In the third, i is 2, etc.

If we want to store the result in a list:

n=10
n_squares = []
for i in range(0, n+1):
  n_squares.append(i**2)

print(n_squares)
## [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

It is not mandatory to use the range() function in a for() loop, you can define the values “by hand”:

message = "The squared value of {} is {}"
for i in [0, 1, 2, 8, 9, 10]:
  print(message.format(i,i**2))
## The squared value of 0 is 0
## The squared value of 1 is 1
## The squared value of 2 is 4
## The squared value of 8 is 64
## The squared value of 9 is 81
## The squared value of 10 is 100

In the same spirit, it is not mandatory to iterate on numerical values:

message = "There is(are) {} letter(s) in the name: {}"
for first_name in ["Pascaline", "Gauthier", "Xuan", "Jimmy"]:
  print(message.format(len(first_name), first_name))
## There is(are) 9 letter(s) in the name: Pascaline
## There is(are) 8 letter(s) in the name: Gauthier
## There is(are) 4 letter(s) in the name: Xuan
## There is(are) 5 letter(s) in the name: Jimmy

Nothing prevents loops from being made inside loops:

message = "i equals {} and j equals {}"
for i in range(0,3):
    for j in range(0,3):
        print(message.format(i, j))
## i equals 0 and j equals 0
## i equals 0 and j equals 1
## i equals 0 and j equals 2
## i equals 1 and j equals 0
## i equals 1 and j equals 1
## i equals 1 and j equals 2
## i equals 2 and j equals 0
## i equals 2 and j equals 1
## i equals 2 and j equals 2

As can be seen, iteration is done for each value of i, and for each of these values, a second iteration is performed on the values of j.

The letters i and j are often used to designate a counter in a for() loop, but this is obviously not a requirement.

In a loop, if we want to increment a counter, we can use the symbol += rather than writing `counter = counter + …`` :

message = "New value for j: {}"
j = 10
for i in range(0, 4):
  j += 5
  print(message.format(j))
## New value for j: 15
## New value for j: 20
## New value for j: 25
## New value for j: 30
print(j)
## 30

7.3 Exercise

  1. Write a very naive program to determine if a number is prime or not. To do this:

    1. define a number variable containing a natural integer of your choice (not too large),
    2. using a loop, check if each integer up to the square root of your number, is a divisor of your number (stop if ever it is the case)
    3. at the loop output, write a conditional instruction indicating whether or not the number is a prime one.
  2. Choose a ‘mystery’ number between 1 and 100, and store it in an object called mystery_number. Then, create a loop that at each iteration performs a random draw of an integer between 1 and 100. As long as the number drawn is different from the mystery number, the loop must continue. At the output of the loop, a variable called nb_drawings will contain the number of draws made to obtain the mystery number.

Note: to draw a random number between 1 and 100, the method randint() of the module random may help).

  1. Use a loop to scan integers from 1 to 20 using a for loop, displaying in the console at each iteration if the current number is even.
  2. Use a for() loop to repeat the Fibonacci sequence until its tenth term (the \(F_n\) sequence is defined by the following recurrence relationship: \(F_n = F_{n-1} + F_{n-2}\); the initial values are \(F_0 = 0\) and \(F_1 = 1\)).