Chapter 20 Logical operators, loops, and exceptions

20.1 Logical operators

Apart from the use of == to test whether two values are equal and the syntax of an if structure, the standard logical operators are all very similar to those in VBA, so we have little more to add to what was presented in lectures. Instead, we will remind the reader of two additional features that we have not seen before.

The in and not in commands are very convenient for testing whether an element is in a list (or set). The following two examples carry out the same task (checking whether an option is available or not) using in and not in respectively.

options = ["Game Theory", "Discrete Maths", "Mathematical Biology"]
   choice = input("Select your preferred optional module: ")
   if choice in options:
       print("Your choice has been accepted")
   else: 
       print("That is not an available option")
options = ["Game Theory", "Discrete Maths", "Mathematical Biology"]
   choice = input("Select your preferred optional module: ")
   if choice not in options:
       print("That is not an available option")
   else: 
       print("Your choice has been accepted")

If we use a variable as an argument in a logical function that expects a Boolean value, then it will be treated as True unless the variable is zero (if it is a number) or empty (if it is a string, list, or set). In the following example we use this to check whether an input string is non-empty.

choice = input("Enter your new password: ")
if choice:
    print("Your password is now", choice)
else:
    print("You have not entered anything")

20.2 For loops and while loops

In lectures we only considered examples where the loop ran over a range or a list (which are the most common cases that we see). It is worth noting that we could also run a loop over a tuple, a set, or even a string.

In the case of a tuple this is entirely straightforward; the only difference from a list is that the individual elements in the tuple cannot be modified. For a set there is no predefined order on the set itself, so you cannot expect that the loop will necessarily run over the elements in the order that you expect. But otherwise the loop behaviour is exactly as for a list.

For a string, the loop will run over the individual characters of the string. An example of this is given below:

x = "Mississippi"
s_counter = 0
for y in x:
    if y == "s":
        s_counter = s_counter + 1
print("The letter s occurs", s_counter, "times in", x)

Generally when we learn about loops we use the for or while structures as explained in lectures, together with the break and continue commands. But just like an if can have an else block following it, so too can a for or while loop. In these cases the else block will run once the initial loop has completed. This option can sometimes be useful — but usually this will need to be combined with the break command.

To see how this can be useful, consider the following example.

for num in range(10, 20):
    for i in range(2, num):
        if num % i == 0:
            j = int(num / i)
            print(num, "equals", i "*", j)
            break
        else:
            print(num, "is a prime number")

This uses a for loop to determine for each number between 10 and 19 either a factorisation or that it is prime. For each such number num the code looks to see whether any number greater than 1 divides num with no remainder. If there is such a number it prints the two factors arising, and quits the inner for loop.

Only if there are no such factors will the inner for loop terminate without using the break command, and so only in that case will it go on to the else part and print that num is a prime number.

The use of an else block at the end of a loop is uncommon, but it is worth remembering that it is possible as it can be very useful.

20.3 Exceptions

There are many possible error messages in Python, and hence many possible exceptions that can arise. Most of these are rather technical, or would be expected to be a result of an error in the way the code has been written rather than something that should occur when the program is being run by a user. Thus we shall not attempt to give a comprehensive list of exceptions that can arise.

We mentioned in lectures two very common exceptions that can occur: ZeroDivisionError and ValueError. We have not yet considered how to use Python to read or write to a file, but when we do then another very common error would be to try to open a file that does not exist, which gives the exception FileNotFoundError.

It is possible to define your own exceptions to catch issues that the standard exceptions do not deal with. For example, you might want to define an exception if an input was negative instead of positive. However, this involves a number of subtleties and is beyond the scope of this module.

An attentive reader may be wondering why the finally option exists for the try...except structure. If the except or the else block of the code run then in both cases the program will continue with the next line occuring after the various blocks of the try structure, so it would seem that the finally block is redundant.

However, this is not quite the case. It may be that an exception arises that is not covered by one of the except blocks that we write into our code. If this happens then the exception will be reported in the console and the program will stop running. But if there is a finally block then this will all be run before the program terminates.

This is useful if you want the program to guarantee to complete certain tasks even if something unexpected happens. For example, a finally block may contain the commands that save the current set of data, or close a file that is being used at that time.

Sometimes you may wish Python to do nothing when an exception occurs (apart from not crash). For example you may be working through a list of data and find one example where there is an error, but just want to ignore that and continue without alerting the user. In such a case the pass command can be used to indicate that nothing happens during that particular except block.

This command has other uses when one is part way through writing some code. When writing exceptions, or loops, or if structures, you may wish to sketch in the body of the code without giving details of what happens in the given block or loop. If you try to write an empty except block, or an empty loop or if structure, then Python will give an error. Using the pass command removes this error, and the command itself can then be used as a visual reminder that you need to return to this section of code and complete it later.