EMAT10006: Further Computer Programming

Functions, exceptions and testing

Functions in a script

# myscript.py

def double(thing):
    """Doubles the thing"""
    return thing + thing

print(double(2))
print(double([1, 2]))
print(double("foo"))

Run in the terminal:

$ python myscript.py
4
[1, 2, 1, 2]
'foofoo'

Functions in a module

# mymodule.py

def double(thing):
    """Doubles the thing"""
    return thing + thing

Run in the Python shell:

>>> from mymodule import double
>>> double(4)
8

Why functions

Case study: datetime module

Python stdlib datetime module: https://github.com/python/cpython/blob/master/Lib/datetime.py

Function naming

Function behaviour

Pure function:

Example:

Categorising functions:

Input/output functions are never pure

Every programme needs to have some inputs and outputs but you should try to put as much as possible of the code in pure functions.

Function names and grammar

Length of function names

Good names

Compare these:

# Call func1
var1 = func1(var2)
# All components are equally weighted
unit_mark = mean(component_marks)

Can you understand what is happening in each example?

Raising exceptions

def get_first_name(student_number):
    """Return first name of the student with this student number"""

    if student_number not in registered_students:
        raise ValueError("No such student registered %s" % student_number)

    details = registered_students[student_number]
    return details['firstname']

Use exceptions when it is not possible to return something sensible

Seeing Exceptions

>>> x = 2
>>> x.upper()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'upper'
>>> 2 + [3]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'list'

Traceback

>>> import subprocess
>>> subprocess.run('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../lib/python3.8/subprocess.py", line 489, in run
    with Popen(*popenargs, **kwargs) as process:
  File ".../lib/python3.8/subprocess.py", line 854, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File ".../lib/python3.8/subprocess.py", line 1702, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'foo'

Traceback demo

Demo...

Make sure you read the traceback!

Catching exceptions

number_string = input("Please enter a number: ")
try:
    number = int(number_string)
except ValueError:
    print("Not a valid number. Found '%s'" % number_string)