User-Defined Functions#

In the case where we want to compute something multiple times but there is no built-in function to rely on, we can write our own function! Replacing multiple lines of code with a function allows seemless reuse of a process or computation.

The general format for defining a function is given below.


def function_name(input_arguments):
    """ Documentation on what your function does """
    
    body of function
    
    return output
  • The def keyword indicates defining a function

  • function_name: We can name our function however we please

  • input_arguments: We decide how many values our function takes as input

  • docstring: We document the key characteristics of our function by using a string - typically triple quotes

  • body of fuction: We perform some computation in the indented body

  • output: The output is returned

When might we use functions? Suppose we’re in the United States working on the Mars probe launch of 1999. We accidentally sent data to our metric loving friends with measurements provided in inches. Let’s make sure the Mars probe doesn’t get lost in space and define a function to convert inches to centimeters before sending that data over.

def convert_inches_to_cm(x_inches):
    """Takes input of inches and converts to centimeters"""
    
    x_cms = x_inches * 2.54
    
    return x_cms

Above we created a function that converts inches to centimeters. Note the input argument of x_inches is taken in and used in the indented body of the function, and the new variable x_cms is returned. But the function does not do anything unless we call it. Now that it is defined, we call it exactly as we would a built-in function - with our function_name followed by parentheses into our input.

convert_inches_to_cm(5)
12.7

Notice we have created this new variable x_cms in our function convert_inches_to_cm. However when we try to print this variable name outside the defined function, as below, we get an error.

x_cms
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[3], line 1
----> 1 x_cms

NameError: name 'x_cms' is not defined

This is because of the scope of a variable, or where a variable is visible to other code. If we define a variable inside the body of a function, it is visible only inside that function.

And remember the docstring we wrote when defining our function? That is accessible to us, or others reading our code, with the help function!

help(convert_inches_to_cm)
Help on function convert_inches_to_cm in module __main__:

convert_inches_to_cm(x_inches)
    Takes input of inches and converts to centimeters

Return vs Print#

Another element to be aware of is the return statement at the end of a function. Creating a similar function that ends with print instead of return, and calling it on an input of 5, as below, it might not be obvious there is a difference.

def convert_inches_to_cm_print(x_inches):
    """Takes input of inches and converts to centimeters"""
    
    x_cms = x_inches * 2.54
    
    print(x_cms)
convert_inches_to_cm(5)
12.7
convert_inches_to_cm_print(5)
12.7

But keep in mind we are working in an interactive Python environment, where the last line of code is printed by default, thus it appears that both functions print their output when in actuality only convert_inches_to_cm_print prints the output.

So, what is the difference between the two function outputs above? The function return statement allows us to store and reuse the output of a function, while the print statement prints the output exactly when the function is called, and the output is not stored. Since the main purpose of a function is to store the function’s output for later potential use in our code, the return statement is very important and powerful.

Therefore the return statement in our first function convert_inches_to_cm, allows for variable assignment to the output of the function. If we try to assign the output of function convert_inches_to_cm_print to a new variable, we find there is no variable to assign.

new_var = convert_inches_to_cm(5)
print(new_var)
12.7
new_var2 = convert_inches_to_cm_print(5)
print(new_var2)
12.7
None

Notice the value of 12.7 is printed in both cells above. The first cell prints 12.7 because we tell it to print variable new_var, the second cell prints 12.7 because it is running through the body of the function, which says to print x_cms, but the variable new_var2 is a NoneType object that has no value.

Functions with Multiple Arguments#

Let’s try another example. Here we write a function that takes two values as input and computes the sum of squares.

def sum_squares(x, y):
    """ Takes two numbers x and y and returns the sum of squares"""
    
    z = x**2 + y**2
    
    return z

Here the function body is defined in terms of x and y, which we must specify when calling the function.

sum_squares(2,1)
5

If we wanted to extend the function sum_squares to calculate the sum of cubes or the sum of any given powers we can make the power itself an argument to the function. Further, we can assume a default option for the exponent to be 2. We do this by assigning our variable a value, in this case a number, in the input_arguments of the function definition. We then have the option to change this argument, or exclude it entirely and use the default option when calling the function.

def sum_powers(x, y, power=2):
    """ Takes two numbers x and y and returns the sum of powers.
    If not specified the default compute the sum of squares, that is power = 2 """
    
    z = x**power + y**power
    
    return z

Calling this function without the power argument gives the same outcome as sum_squares, but when we include an additional argument of 3, we’re computing the sum of cubes!

sum_powers(2,1)
5
sum_powers(2,1,3)
9

Argument Order#

The order of the arguments does matter when calling a function. If we switch order of inputs 1 and 3 we do get a different answer.

sum_powers(2,3,1)
5

If we want to more explicit about which variable in which in our input, we can call the function with the given function variables assigned. This allows us to rearrange the order of inputs without affecting the function output.

sum_powers(x=1, y=2, power=3)
9
sum_powers(x=1, power=3, y=2)
9

Functions are extremely important and useful methods to reuse, organize, and simplify code. We will see functions used throughout this textbook. As we explore more Python, we will find that functions are very versatile and can be applied to many different objects while streamlining repeatable processes.