Pre-MAP Course Website | Pre-MAP GitHub | Google

Writing Functions Python

You have already seen how to use built-in modules (e.g. numpy) in python and the functions that accompany them. Now we will learn how to write our own functions.

Functions

Functions in python are of the following form:

def function_name(argument_1, argument_2,..., keyword_argument_1=val1, keyword_argument_2=val2, ...)

Where argument_1 and argument_2 are "arguments" and are required, and keyword_argument_1 and keyword_argument_2 are called "keyword arguments" and are optional. The names of python functions can be any combination of lowercase letters, numbers and underscores as long as they don't start with a number, and as long as they are not already the name of a built-in keyword (i.e. print). Let's look at a very simple example of a function:

First example: the add function

Let's start with a simple function:

def add(x, y):
    """This function adds x to y."""
    return x + y

This function adds the argument x to the argument y. You indicate that you're defining a function with the def statement, then comes the name of the function, then (no spaces here) comes parentheses containing the arguments.

The arguments x and y are symbols -- a user could call the function on variables that they define, which need not be called x and y. Here, they just define that within the function, you will refer to the first argument as x and the second as y.

The return line needs to be indented with respect to the def line. Next to the word return, you write the result that you want the function to output.

The line in triple-quotes is called a docstring. It is documentation, or user instructions. Most Python functions contain information in the docstring that will help you figure out how to use the function.

We can now call this function like so:

def add(x, y):
    """This function adds x to y."""
    return x + y

a = 5
b = 10

a_plus_b = add(a, b)

print(a_plus_b)

Note that the variables that are defined within a function (x and y in this example), cannot be accessed outside of the function. If you try to print x at the bottom of the code above, you'll see:

NameError: name 'x' is not defined

because the variable name x only exists within the function. This concept is called scope.

Exercise 1

In the cell below, copy and paste the recipe above for addition. Modify it to multiply two numbers together, and don't forget to change the function name and docstring accordingly.


In [ ]:

That example is just for demonstration purposes, of course. But there are times when you want to do something more complicated. Let's now make a function that does something more complicated - one that takes a list of numbers as its argument, and returns a list of only the even numbers.

def only_evens(list_of_numbers):
    """Take a list of numbers, and return a list of only the even numbers"""

    # This is an empty list that we'll append the even numbers onto
    even_numbers = []

    # Go through each number in the list of numbers
    for number in list_of_numbers:

        # If this number is an even number:
        if number % 2 == 0:

            # Append it to the list of even numbers
            even_numbers.append(number)

    # Then return the number
    return even_numbers

Exercise 2

Copy and paste the only_evens function above into the cell below, and try it out using a list of numbers that you can create however you like (make it up!). Test that the function works. Turn to your neighbor and practice explaining how the function works to one another. Group work is encouraged!


In [ ]:

Now why is this useful? This is helpful when you need to do the same procedure a bunch of times. If I wanted to get the even numbers out of 20 lists of numbers, I would have to re-write everything in the function above 20 individual times. However, I can call the only_evens function with only one line each time that I want to use it, like this:

evens_1 = only_evens(numbers_1)
evens_2 = only_evens(numbers_2)
evens_3 = only_evens(numbers_3)
...

Exercise 3: numpy review

This is a good place to remind you that when you have lists of numbers, you could turn them into numpy arrays, and use their special powers to do your work. In Exercise 2, you worked with a program that goes through a list of numbers to tell you which ones are even. You might recall that in the lesson on numpy, in Exercise 6, we figured out which numbers were even and odd for an entire numpy array at once.

Refer back to the numpy lesson, and in the cell below, re-write the only_evens function to use numpy, instead of a for loop. Call this new function only_evens_numpy. Run it on the list of numbers and show that it works.

Hint: Don't forget to import numpy, with the line

import numpy as np

In [ ]:

One of the questions you might be asking yourself is: "why do we use numpy if we can just write the functions ourselves?" One reason is that it's usually faster to write these operations with numpy (see above, the numpy version has fewer lines of code).

The real reason is that numpy is way faster than pure Python without numpy. Let's demonstrate that here.

Exercise 4: Benchmarking

We're going to use a function in numpy to make a really big list of numbers for this exercise. In the cell below, execute:

lots_of_numbers = np.random.randint(0, 100, 100000)
print(lots_of_numbers)

That will create an array of 100,000 random numbers between zero and 100.

We're now going to run our two only_even and only_even_numpy functions on lots_of_numbers, to see which one is fastest. To time a function in an iPython Notebook, you use the %timeit magic function, like this:

%timeit only_evens(lots_of_numbers)
%timeit only_evens_numpy(lots_of_numbers)

The output tells you how long it takes to run each function (usually in units of ms=milliseconds).

How much faster is the numpy version? (This is why we use numpy!)


In [ ]:

Exercise 5: Modules

Let's say only_evens and only_evens_numpy were complicated functions that took hundreds of lines of code to write. You might want to keep them in their own Python script (their own file), and import them into the notebook where you use them. In this exercise, we'll practice doing that.

  1. Run gedit from your command line, and save a file called mymodule.py in the same directory as this notebook.
  2. Copy the function definitions for only_evens and only_evens_numpy and save them into the mymodule.py file.
  3. In the cell below, run import mymodule to import the functions from your module into this python script.
  4. You can now run each function by calling mymodule.only_evens or mymodule.only_evens_numpy in this notebook. Try that below:

In [ ]:

That's how every Python package is written – it's Python code that you import into your notebook or scripts.

Exercise 6: King Arthur

King Arthur and the knights seek refuge in a French castle, but things don't work out so great.

Create a function that takes an input argument, which will be a string containing a statement by King Arthur. The function will return a response from the French knight.

Here's one example:

def frenchmans_response(arthur_says):
    """This function responds to King Arthur."""

    if arthur_says == "Well, what are you, then?":
        response = "I'm French! Why do you think I have this outrageous accent, you silly king?"
    elif aurther_says == "What are you doing in England, then?":
        response = "Mind your own business!"
    else: 
        response = "I DON'T WANT TO TALK TO YOU NO MORE."

    return response

arthur_quote = "Well, what are you, then?"
answer = frenchmans_response(arthur_quote)
print(answer)
I'm French! Why do you think I have this outrageous accent, you silly king?

Get creative and make your own function, and test that it produces the appropriate output.


In [ ]:


In [ ]:


In [ ]: