Some of the computer programs encountered so far consisted of a number of statements that were executed once, in the order in which they were written in our .py files. Conditional statements introduced some exceptions to this rule, and allowed us to "skip" some lines of code, depending on whether some conditional statements were evaluated as 'True' or 'False'.
In this unit we are going to consider Python statements that implement loops, where some statements may be executed multiple times, depending on certain conditions; this will become clearer as we go along.
Computer scientists use the phrase control flow (or the 'flow of execution') to refer to the sequence of steps executed by a computer program. Both conditionals and loops allow us to change the control flow (recall the flowlines that we encountered in the flowcharts discussed in Week 1).
'Loops' in programming languages can be divided into two categories: definite and indefinite loops, respectively.
A for-loop allows you to iterate through a sequence of values, and corresponds to the design pattern mentioned below:
for <var> in <sequence>:
<body>
The loop index variable 'var' takes on each successive value in the sequence, and the statements in the body of the loop are executed once for each value. Note the use of the Python keyword in.
Here are a couple of basic examples:
# first loop:
for i in 1,2,3,4,5: # 1,2,3,4,5 corresponds to <sequence>
print(i) # i corresponds to <var>
# print(i) represents the <body>
# another loop -- this does nothing!
for k in 1,2,3:
pass # Python keyword
The first loop will execute five times. There are five values in the set of values to work with, so it goes through each of them once. The body of the loop contains a 'print' statement that displays the value of the index variable each time it executes the loop. The second loop is very similar, but this time the body of the loop contains the keyword pass. In plain English, this informs Python to pass the line without doing anything.
You don't have to list every value in the set of values over which to execute; there are better ways to achive this, and we are going to look at some of these over the next few weeks.
Python comes with a built-in function called range. This allows you to define an ordered sequence of numbers. You have control over the starting and ending values in your sequence, as well as the so-called step (i.e., every "how many numbers to skip"). The general syntax is:
range(start, end, step) # 'step' is optional; default value is 1
range(4) # 0, 1, 2, 3
range(3,7) # 3, 4, 5, 6
range(3,12,2) # 3, 5, 7, 9, 11
range(2,9,2) # 2, 4, 6, 8
range(6,2,-1) # 6, 5, 4, 3
Let's say you want to add the numbers from 1 to a given value N. A for-loop together with the 'range' function allows you to do this very easily:
"""
Example to calculate the sum of the first N natural numbers
"""
N =int(input('Give a number between 1 and 20: '))
total = 0 # variable that will store the result
for i in range(1, N+1): # the sequence is 1,2,3,..., N-1, N
total = total + i
# well-known formula:
# 1 + 2 + ... + N = 0.5*N*(N+1)
total_other = int(0.5*N*(N+1))
print("Computed result: ", total) # display the result on the screen
print("Formula result: ", total_other) # display the formula result
The variable 'total' used above is sometimes referred to as an accumulator variable because it is used to store the final result by "accumulating" values. A programming construct like the one above is known as the 'accumulator pattern' and can be used to calculate any sum (or product) of terms.
"""
Another example of for-loop:
Compute the factorial of a positive integer
"""
N = int(input('Give an integer less than 10: ')) # interactive user input
# N = 8 # non-interactive user input
fact = 1 # initialise the result
for factor in range(N,0,-1):
fact = factor*fact # 'fact' will contain N! when the loop finishes
print('The factorial of', N, 'is:', fact) # output on the computer screen
The next example illustrates the idea of nested for-loops.
We want to write a computer code that determines the number of primes between 1 and some given number N. A prime number is a number that is divisible only by 1 and itself. It turns out that you can determine if a number is prime by trying to divide it by all the numbers between 1 and N/2. A couple of for-loops can handle this task effortlessly:
# Find the primes between 1 and N
N=38 # (non-interactive) user input
for n in range(2, N):
prime = True
for d in range(2,n):
if (n%d == 0):
prime = False
if prime == True:
print(n," is a prime number")
This code is not very efficient because even after it determines that a given number is not prime, it continues to find factors that divide into it. The code should probably stop processing the inner loop as soon as it finds that a number is not prime. Python has some special syntax for this, in the form of a keyword named break. Here's the revised version of the above code:
# (upgraded version of the above code)
# Find the primes between 1 and N
N=10 # (non-interactive) user input
for n in range(2, N):
prime = True
for d in range(2,n):
if (n%d == 0):
prime = False
break
print("Inner loop: ", d)
if prime == True:
print(n," is a prime number")
The 'break' keyword stops the processing of a loop and breaks out of it when the statement is encountered. The new 'print' statement in the inner loop is included so that you can see what is going on when the loop executes. As soon as a factor that the number divides by evenly is found, then the loop stops.
There is another important keyword that is somewhat related to 'break', but has quite different meaning. Let assume that you want to process only odd numbers in a given range. You can write something like this:
for i in range(2,12):
if (i%2 != 0): # here we exclude the ODD numbers, etc
print('Processing', i)
print('Doing something....')
else:
print('Not processing', i)
Python provides the keyword continue to achieve the same as the above code. Study the next piece of code (an upgrade of the above example):
for i in range(2,13):
if (i%2 !=0 ): # here we exclude the ODD numbers, etc
continue # note the use of the new keyword
print('Processing', i)
print('Doing something ....')
This example shows how the if-statement can be used within a Python for-loop to do individual processing on range elements.
Sometimes you may want your computer program to execute a certain block of code for as long as some conditions is true. In this case you should use a while-loop. The design pattern for this is:
while <conditional statement>:
<body>
If the Boolean expression that appears in the conditional statement evaluates to 'False', Python does nothing; it simply moves to the statement that follows the body of the loop. If the expression evaluates to 'True', Python executes the block of statements in sequence, but then checks the expression again, executes the sequence of statements again if the expression evaluates to 'True', and continues doing this as long as the expression evaluates to 'True'. Thus, the flow of control loops back to the Boolean expression repeatedly. The indented statement block within a while statement is referred to as the 'body of the loop'; the Boolean expression in the conditional statement represents the 'loop-continuation condition'.
Recall the discussion from Week 1 when we met this programming construct in the context of pseudocode: the body of the loop should change one or more variables used in the loop-continuation condition, in order to have a chance of eventually getting that conditional statement evaluate to 'False'. Otherwise, the loop will keep on going indefinitely.
"""
Basic example of using the 'while' loop
"""
i=1 # create the variable i
while (i <= 5):
print(str(i)+'th Hello')
i = i + 1 # the body changes i
(OK, the first three messages displayed on the screen are not grammatically correct, but you get the idea.... You can rectify this by adding some 'if-statements'.)
The next example shows how to use a 'while-loop' construct in order to construct a series of powers of 2 (you can achieve the same using 'for-loops'). Here's the code:
"""
Powers of two (using a 'while-loop'):
"""
n = 9 # user input
power = 1 # initialise 'power'
i = 0 # don't forget about 'i'..... must be initialised!!
while (i <= n):
print(str(i)+ ' '+str(power))
power = 2*power
i = i + 1
The next code finds the prime factors of a given integer. For example:
$$ 45262721920 = 2^7\times 5 \times 13\times 43 \times 126517 $$
"""
Prime factorisation for any positive integer
"""
N = int(input('Give a natural number: '))
factor = 2
while (factor*factor <= N): # only need to check factors <= sqrt(N)
while (N%factor == 0): # N divisible by factor?
N = N//factor
print(str(factor)+' ')
factor = factor + 1 # increment factor
if (N > 1):
print(N)
print('')
REFERENCE:
T. Gaddis, Starting out with Python (Fourth Edition), Pearson Education Ltd., 2018