Functions and Classes in Python

Functions

Overview:

  • Teaching: 10 min
  • Exercises: 10 min

Questions

  • What is a function?
  • How can I define new functions?
  • What’s the difference between defining and calling a function?
  • What happens when I call a function?

Objectives

  • Define a function that takes parameters.
  • Return a value from a function.
  • Test and debug a function.
  • Set default values for function parameters.
  • Explain why we should divide programs into small, single-purpose functions.

What are functions?

Functions provide a way to package often-used code into reusable and easy to use components. For example, here is some code that multiplies together two lists

In [1]:
list1 = [2, 4, 6, 8]
In [2]:
list2 = [10, 20, 30, 40]
In [3]:
list3 = []
In [4]:
for x, y in zip(list1,list2):
    list3.append(x * y)
In [5]:
list3
Out[5]:
[20, 80, 180, 320]

We don't want to keep typing out the above code every time we want to multiply the numbers in two lists. Instead, we can collect that code together into a function

In [6]:
def multiply(a, b):
    c = []
    for x,y in zip(a,b):
        c.append(x*y)
    return c

We can now call this function directly on our lists, e.g.

In [7]:
list3 = multiply(list1, list2)
In [8]:
list3
Out[8]:
[20, 80, 180, 320]

The function is called using its name, and passing in the values as two arguments, e.g.

In [9]:
list4 = multiply( [1,2,3], [4,5,6] )
In [10]:
list4
Out[10]:
[4, 10, 18]

The arguments are placed inside the round brackets. These are copied, in order, to the function. For example, [1,2,3] is copied into a, and [4,5,6] is copied as b. The code in the function is then executed. We can watch this code being run by adding in print statements, e.g.

def multiply(a, b):
    print("a = %s" % a)
    print("b = %s" % b)
    c = []
    for x,y in zip(a,b):
        print("%s times %s equals %s" % (x,y,x*y))
        c.append(x*y)
    print("c = %s" % c)
    return c

You must pass the right number of arguments into a function. For example, this is what happens if you get the number of arguments wrong...

In [11]:
list5 = multiply(list1)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-e851918351e0> in <module>
----> 1 list5 = multiply(list1)

TypeError: multiply() missing 1 required positional argument: 'b'

You can write functions that take as many (or as few) arguments as you want. For example, here is a function that takes no arguments, and then a function that takes lots

In [12]:
def func0():
    return "no arguments to this function"
In [13]:
def func1(a, b, c, d, e=5):
    return a+b+c+d+e
In [14]:
func0()
Out[14]:
'no arguments to this function'
In [15]:
func1(1, 2, 3, 4, 5)
Out[15]:
15
In [16]:
func1(1, 2, 3, 4)
Out[16]:
15

Note that with the last function we have set a default value of the argument e. This is given the value of 5 if it is not specified. This allows us to pass 4 arguments instead of 5. Changing the default value by editing the definition of the function above will thus change the output of func1 when it is called with only four arguments.

Exercises

Here is the morse code dictionary from the last session, together with the code that converts a message from English into morse code.

In [17]:
letter_to_morse = {'a':'.-', 'b':'-...', 'c':'-.-.', 'd':'-..', 'e':'.', 'f':'..-.',
                   'g':'--.', 'h':'....', 'i':'..', 'j':'.---', 'k':'-.-', 'l':'.-..', 'm':'--',
                   'n':'-.', 'o':'---', 'p':'.--.', 'q':'--.-', 'r':'.-.', 's':'...', 't':'-',
                   'u':'..-', 'v':'...-', 'w':'.--', 'x':'-..-', 'y':'-.--', 'z':'--..',
                   '0':'-----', '1':'.----', '2':'..---', '3':'...--', '4':'....-',
                   '5':'.....', '6':'-....', '7':'--...', '8':'---..', '9':'----.',
                   ' ':'/' }
In [18]:
message = "SOS We have hit an iceberg and need help quickly"
In [19]:
morse = []
for letter in message:
    morse.append( letter_to_morse[letter.lower()] )
print(morse)
['...', '---', '...', '/', '.--', '.', '/', '....', '.-', '...-', '.', '/', '....', '..', '-', '/', '.-', '-.', '/', '..', '-.-.', '.', '-...', '.', '.-.', '--.', '/', '.-', '-.', '-..', '/', '-.', '.', '.', '-..', '/', '....', '.', '.-..', '.--.', '/', '--.-', '..-', '..', '-.-.', '-.-', '.-..', '-.--']

1

Create a function called encode that takes a message and returns the morse code equivalent. Test this function by encoding the message SOS We have hit an iceberg and need help quickly and check that you get the same result as in the last session. Now try using your function to encode other messages.

Solution

2

Using the solution from Exercise 2 in the dictionaries lesson, write a function called decode that converts a morse code message back to english. Check that you can decode the above morse code message back to English.

Solution

3

Below is a list of messages. Loop over the messages and check that encode( decode(message) ) equals the original message. Do any of the messages fail to encode and decode correctly? If so, why? How can your check be modified to account for the limitations of your encode and decode functions?

messages = [ "hello world", "this is a long message", "Oh no this may break", "This message is difficult to encode." ]

Solution

Key points:

  • Define a function using def function_name(parameter).
  • The body of a function must be indented.
  • Call a function using function_name(value).
  • Variables defined within a function can only be seen and used within the body of the function.
  • If a variable is not defined within the function it is used, Python looks for a definition before the function call.
  • Use help(thing) to view help for something.
  • Put docstrings in functions to provide help for that function.
  • Specify default values for parameters when defining a function using name=value in the parameter list.
  • Parameters can be passed by matching based on name, by position, or by omitting them (in which case the default value is used).
  • Put code whose parameters change frequently in a function, then call it with different parameter values to customize its behavior.