Lesson 5: Program control structures - loops and conditions
Program control structures (or just control structures) are language syntactic structures that allow conditional and repetitive execution of a sequence of commands.
Logical expressions
A logical expression (or logical statement) is any statement to which a logical value (true/false) can be unambiguously attributed, ie to determine whether it is true or false. Assigning a logical value to a given expression is called its evaluation. Logical expressions are used in programming wherever a command (or series of commands) needs to be executed only if a certain condition is met (such commands are called conditional statements). The condition then takes the form of a logical expression, while its fulfillment/non-fulfillment is given by the logical value of the expression.
By comparing two values, it is possible to create a simple logical expression:
>>> 3 < 5
True
>>> 3 > 5
False
You can also compare text strings. The comparison is then based on alphabetical order (ie on the so-called lexicographic ordering), with uppercase letters having priority over lowercase ones:
>>> "hello" < "world"
True
>>> "Hello" < "HELLO"
False
Equality is tested by the ==
operator (be careful not to confuse it with the =
operation, which assigns a value to a variable!):
>>> a = 5
>>> a == 5
True
The inequality is tested with either !=
or <>
operator:
>>> a != 5
False
>>> a <> 3
True
The is
comparison operator is a bit more complicated. For numbers and strings, it tests equality in the same way as ==
, but for more complex objects, such as lists, it tests the identity of the objects (ie, whether they are the same object with the same address in memory):
>>> a = 3
>>> b = 3
>>> a is b
True
>>> a = [1,2,3]
>>> b = [1,2,3]
>>> a is b
False
>>> a = b
>>> a is b
True
The opposite of is
is the is not
operator.
The in
operator tests whether a certain element is in a given list or a certain character in a given string:
>>> a = [1,2,3]
>>> 2 in a
True
>>> "o" in "hello"
True
Its opposite is not in
:
>>> a = [1,2,3]
>>> 4 not in a
True
>>> "z" not in "hello"
True
Compound logical statements can be created from simple ones using the so-called logical operators and
, or
and not
(we are talking about so-called logical operations with logical expressions). The meaning of these operators is generally known from basic courses on logic, so we will limit the interpretation to a small example. E.g. if we want to test whether a value of a numeric variable is contained in a certain list and at the same time whether it is greater than 3, this can be done using the and
operator:
>>> mylist = [1,2,3,4]
>>> a = 4
>>> a in mylist and a > 3
True
The structure of a compound expression can be arbitrarily complex, containing any number of partial simple and complex expressions. If subexpressions are also compound, the priority of operations can be controlled using parentheses:
>>> a in mylist and (a > 3 or a < -3)
True
The use of parentheses is governed by the known priority of operations: not
is always evaluated first, then and
, then or
. If we omitted the parentheses in the last example, the meaning of the expression would change (answer: how?).
Task 1. Enter the following command:
s = [1, 4, -10, 6, 13, -2]
. Decide in advance about the following expressions, whether they are true or false. Then verify:
s[1] < s[3] or 3 in s and len(s) == s[3]
s[1] < s[3] or (3 in s and len(s) == s[3])
(s[1] < s[3] or 3 in s) and len(s) == s[3]
s[1] > s[3] and 3 not in s or len(s) == s[3]
s[1] > s[3] and (3 not in s or len(s) == s[3])
(s[1] > s[3] and 3 not in s) or len(s) == s[3]
s[1] > s[3] and not (3 not in s or len(s) == s[3])
not (s[1] > s[3] and 3 not in s) or len(s) == s[3]
s
Conditional statements
A statement or command is called conditional if its execution only happens if a certain condition is met. The condition can be any logical expression, and the fulfillment of the condition is given by its logical value. The syntax of conditional statements in Python is very intuitive, as it copies the syntax of the common language: if the condition is met, execute the following command(s):
if condition: command
In case of multiple commands:
if condition:
command 1
command 2
command 3
...
Here we see the block structure of code based on mandatory indentation, something typical and specific for Python langauage. Complying statements are indented one level (= four spaces) to the right of the line with the keyword if
. Any statement indented to the level of the word if
will no longer be related to the condition, ie it will be executed regardless of its fulfillment or non-fulfillment.
Let's give an example:
>>> a = 5
>>> b = 6
>>> if a < 6: print a
5
>>> if b < 6: print b
>>> if a < b:
print a
print b
print a, "is less than", b
5
6
5 is less than 6
When writing a conditional statement to the Python Shell window, one needs to press the
Enter
key twice to execute the code. By pressing theEnter
key a second time, we tell the interpreter that we have finished writing and the whole block can be interpreted (ie executed). This is why there is always one blank line after the last line of the notation.
In addition to specifying what commands to execute if a condition is met, you can also tell the program what commands to execute if the condition is not met. The syntax is intuitive again: if the condition applies, execute the following command(s), else (meaning "otherwise") execute alternative command(s):
if condition:
command 1
command 2
else:
command 3
command 4
This time we show an example in the form of a script:
a = 5
b = 6
if a == b:
print(str(a) + " equals " + str(b))
else:
print(str(a) + " does not equal " + str(b))
After running the script, the Python Shell console returns:
5 does not equal 6
It is also often the case that we need to gradually test several different conditions, under each of which corresponding commands should be executed. The structure of the notation is: if condition 1 applies, execute command(s) 1, else if condition 2 applies, execute command(s) 2, else execute command(s) 3. There can be any number of conditions chained in this way, optionally with the final else section at the end, followed by statements executed if none of the previous conditions are met.
One way to implement the scheme described above is as follows:
a = 5
b = 6
if a == b:
print a, " equals ", b
else:
if a < b:
print a, " is less than ", b
else:
print a, " is greater than ", b
As can be seen, when concatenating the conditions this way, each further condition is indeted one level deeper. If there is more than few conditions this might result in an unclear and not very nice code. Fortunately, there is an alternative notation in Python that uses the elif
keyword, which is actually an abbreviation of else if
. The usage is evident from the following example (again, the sequence if
-elif
-elif
-...-elif
may or may not end with the else
part):
a = 5
b = 6
if a == b:
print a, " is equal ", b
elif a < b:
print a, " is less than ", b
else:
print a, " is greater than ", b
Task 2. Write a script that decides for given two numbers whether the larger one is divisible by the smaller one.
The while
loop
Sometimes we need to execute a command or series of commands repeatedly until a certain condition is occurs (or, conversely, expires). The while loop is used for this. In Python, its syntax is as follows:
while condition:
command 1
command 2
...
command n
As long as the condition is valid, the sequence of commands 1, 2, ..., n will be executed repeatedly. It is important that within these commands sooner or later something happens so that the condition no longer applies. Otherwise, a so-called infinite loop would arise. We would then have to forcibly interrupt the program with the keyboard shortcut Ctrl
+ C
, or as a last resort, use the Windows Task Manager to terminate the task.
An example of using the while
loop is calculation of the factorial of a given natural number, for example 20:
n = 20
fact = 1
i = 2
while i <= n:
fact = fact * i
i = i + 1
print(fact)
The condition for the continuation of the loop is the validity of the statement i <= n
. This statement will certainly cease to be valid once, because in each step the value of the variable i
is increased by one unit, so that once it will definitely exceed the value of n
. Once this happens, the loop will no longer be executed and the program will continue executing statements (if there are any) written after the loop, ie indented to the level of the word while
. In our case, it prints the result to the Python Shell console:
2432902008176640000
Of course, for different values of the variable n
we get different results of the factorial.
The while
loop can actually be considered a special kind of conditional statement, because it determines what the program should do if a condition is met. It can even be combined with the else
clause, followed by a sequence of statements to be executed if the condition is no longer met (ie after the end of the loop):
while condition:
commands 1 to n
else:
commands n + 1 to m
It can be argued that the program will behave in the same way if we write the commands n + 1 to m after the loop to the level of the word while
instead of into the else
section. This is true and the use of else
in the while
loop is actually very rare. However, this option is not entirely without purpose, as we will see later when we explore the break
and continue
commands.
Task 3. Create a list with a Fibonacci sequence of length 100 using a
while
loop.
The for
loop
We use the for
loop wherever we want to iterate over a list and do something with each of its items. The syntax is as follows:
for item in list:
command 1 (in which the variable item can be used)
command 2 (in which the variable item can be used)
...
E.g. we can easily print individual items of the list:
mylist = [0, "one", 2, "three", 4, "five"]
for i in mylist:
print (i)
The result is:
0
one
2
three
4
five
The same task could be solved using a while
loop:
i = 0
while i < len(mylist):
print mylist[i]
i = i + 1
The for
cycle can be used wherever we know in advance how long our loop will be (ie how many iteration it will have). If, for example, we want to repeat a sequence of commands 20 times, it is enough to make a list of a given length and go through it using the for
cycle. We do not have to use the items of the browsed list in individual commands at all:
for i in [1]*20:
print ("I won't interrupt the class with a loud croacking.")
When executed, it returns:
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
I won't interrupt the class with a loud croacking.
It is often useful to iterate over a list of integer numbers from one to n (for example up to twenty). The range
function can be useful for this:
>>> range(20) # Returns a list of length 20, starting with zero
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> range(5, 10) # Returns a list from 5 to 9
[5, 6, 7, 8, 9]
>>> range(5, 50, 3) # Returns a list from 5 to 49 with step of 3
[5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47]
>>> range(50, 5, -3) # Returns a list from 50 to 6 with step of -3
[50, 47, 44, 41, 38, 35, 32, 29, 26, 23, 20, 17, 14, 11, 8]
The above calculation of the factorial could therefore also look like this:
n = 20
fact = 1
for i in range(1, n+1):
fact = fact * i
print(fact)
The for
loop can also be enclosed in square brackets to create a list. The following code creates a list of squares of numbers from 1 to 10:
>>> a = [x**2 for x in range(1,11)]
>>> a
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Of course, we could create the same list less briefly:
>>> a = []
>>> for x in range(1,11): a.append(x**2)
>>> a
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
The first method is obviously more elegant and so it is more often used by experienced programmers.
Task 4. Create a list with a Fibonacci sequence of length 100 using the
for
loop.
The break
andcontinue
commands
The break
and continue
commands are used to interrupt a loop if there is a reason to do so. Therefore, they are typically used as part of a conditional statement, as can be seen from the following schematic representation of the syntax of the break
command (we state both the version with the while
and with the for
loop):
# Version with the while loop:
while condition 1:
the first series of commands
if condition2:
second series of commands
break
else:
the third series of commands
else:
fourth series of commands
fifth series of commands
# Version with the for loop:
for item in list:
the first series of commands
if condition 2:
second series of commands
break
else:
the third series of commands
else:
fourth series of commands
fifth series of commands
`` `
Note that the first `else` refers to the `if` statement, while the second `else` refers to the `while` or `for` loop.
The `break` statement causes an immediate break in the loop, and if there is (which may not!) also an `else` part related to the cycle, the program continues after it. In our schematic example, this means that as soon as in some step (iteration) of the loop the condition 2 applies, ie the command `break` is executed, the program automatically interrupts the cycle and continues by executing the fifth series of commands. On the other hand, if the condition 2 is never met during the loop, then after the loop the program continues with the fourth series of commands.
An example of using the `break` command with the `for` loop can be a script looking for a specific item (eg number 20) in a list:
```python
for number in mylist:
if number == 20:
print ("I just found number 20!")
break
else:
print("Number 20 is not in the list!")
The continue
statement causes only the currently running iteration to be interrupted, and the program continues with the next step (iteration), skipping thus all the commands in the loop that are after the continue
statement. It is used less often than the break
command, because in most cases its use can be replaced by a suitably chosen conditional command. For this reason, we don't provide an example.
Summary
Tasks
- From the sequence created by solving task 3 resp. 4, create a list containing only members divisible by three and determine its length.
- Write a script that for given two lists of lengths m and n, where m > n, creates a new list, the first n elements of which will be formed by the elements of the shorter of the two lists, the rest of the list will be completed with elements of the longer of the two lists. Create a solution that works when you enter any two lists in any order.
- Write a script to compare two numeric lists "item by item". The entry into the program will be any two lists and the type of comparison ("greater than", "less than" or "equals"). The output will be a list of the length of the shorter of the two lists, which on the index i will contain the result of the comparison (
True
/False
) of the respective items of the input lists. E.g. for listsa = [1,2,3]
andb = [1,-2,4,5]
the "greater than" comparison will result in a list[False, True, False]
. - Write a script that decides whether given two numbers have a common divisor.