Functions#

Function definitions#

Functions are chunks of code that you can reference whenever you need.
This function just prints out a statement

def my_hello_function():
    print('hello world')

We write def to define the function, followed by the name we choose for the function, my_hello_function, parentheses, a colon, and then an indented section.

To use the function we just created, simply run the following (yes we need the parentheses):

my_hello_function()
hello world

In fact, we can use it many times:

my_hello_function()
my_hello_function()
my_hello_function()
hello world
hello world
hello world

Function arguments and return values#

We can also pass arguments to functions. Think of arguments as inputs to the function.

This example takes two arguments: title_input and name_input:

def custom_hello(title_input, name_input):
    print('Hello', title_input, name_input, '!')

And we can use it like this:

custom_hello(title_input='Professor', name_input='Beardsley')
Hello Professor Beardsley !
custom_hello(title_input='Señor', name_input='Loadenstein')
Hello Señor Loadenstein !

Functions can also return or output values that you can store and later reference.

This function has three inputs and one output:

# define the function
def some_math(x_input, y_input, z_input):

    # calculate the result
    my_result = x_input**y_input - z_input

    # return the result variable
    return my_result

Reminder, this is just the function definition. We haven’t actually used the function yet. In order to use the function, we need to call it and pass it some arguments. When we do that, it will pass the output back to us.

Now let’s use our new function and store the output in answer_1.

answer_1 = some_math(x_input=4, y_input=2, z_input=6)
answer_1
10

We do not need to explicitly name the inputs. If we are careful to pass the arguments in the correct order, then the following will also work.

answer_1 = some_math(4, 2, 6)
answer_1
10

However, that is not the recommended approach since it is easy to get the order of the arguments/inputs wrong. It is also easier to read and understand the code when we explicitly use the names of the arguments.

Another benefit of using the names of the arguments is that we can pass the arguments in any order we want.

answer_1 = some_math(y_input=2, z_input=6, x_input=4)
answer_1
10

Important

We can pass named arguments or unnamed arguments into functions. If we do not use the names of the arguments, then be careful to have the order of the arguments correct.

Arguments with default values#

If you want your function to have optional arguments with default values, you can include them in the function definition like this.

# define the function with default values
def calculate_sharpe(return_input=0.09, st_dev_input=0.04):
    # calculate the sharpe ratio using the inputs
    sharpe_ratio = return_input / st_dev_input
    # print the result
    print('Sharpe Ratio:', sharpe_ratio)
    # this function does not "return" anything

Notice how we can include arguments when we use this function:

calculate_sharpe( return_input=0.12, st_dev_input=0.1 )
Sharpe Ratio: 1.2

But we don’t have to. In this case, the function will use the default values of 0.09 and 0.04.

calculate_sharpe()
Sharpe Ratio: 2.25

Example#

Below is a math function that combines several of the previous topics.

This is known as the \(3x+1\) problem.

  • pick any starting number

  • if the number is odd, multiply by 3 and add 1

  • if the number is even, divide by 2

  • repeat the process with the new number

  • you will always arrive at a value of 1 eventually

See here for a YouTube video.

# define the function
def fun_function(starting_value):
    # set some initial values
    counter = 0
    current_num = starting_value
    max_value = starting_value
    process_list = [current_num]

    while current_num != 1:
        # do something if the number is odd
        if current_num % 2 == 1:
            current_num = current_num * 3 + 1

        # do something if the number is even
        elif current_num % 2 == 0:
            current_num = current_num / 2

        else:
            print('something went wrong')
            counter = 'error'
            break

        counter = counter + 1

        # if the current number is a new max, then update the max
        if current_num > max_value:
            max_value = current_num

        # add the current number to the process list
        process_list.append( int(current_num) )

    print('Ended up at 1 after', counter, 'steps.')
    print('Process reached max value of', int(max_value) )
    print(process_list)

Now let’s use the function we just defined.

fun_function(10)
Ended up at 1 after 6 steps.
Process reached max value of 16
[10, 5, 16, 8, 4, 2, 1]
fun_function(500)
Ended up at 1 after 110 steps.
Process reached max value of 9232
[500, 250, 125, 376, 188, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364, 182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790, 395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566, 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]
fun_function(987654)
Ended up at 1 after 183 steps.
Process reached max value of 2222224
[987654, 493827, 1481482, 740741, 2222224, 1111112, 555556, 277778, 138889, 416668, 208334, 104167, 312502, 156251, 468754, 234377, 703132, 351566, 175783, 527350, 263675, 791026, 395513, 1186540, 593270, 296635, 889906, 444953, 1334860, 667430, 333715, 1001146, 500573, 1501720, 750860, 375430, 187715, 563146, 281573, 844720, 422360, 211180, 105590, 52795, 158386, 79193, 237580, 118790, 59395, 178186, 89093, 267280, 133640, 66820, 33410, 16705, 50116, 25058, 12529, 37588, 18794, 9397, 28192, 14096, 7048, 3524, 1762, 881, 2644, 1322, 661, 1984, 992, 496, 248, 124, 62, 31, 94, 47, 142, 71, 214, 107, 322, 161, 484, 242, 121, 364, 182, 91, 274, 137, 412, 206, 103, 310, 155, 466, 233, 700, 350, 175, 526, 263, 790, 395, 1186, 593, 1780, 890, 445, 1336, 668, 334, 167, 502, 251, 754, 377, 1132, 566, 283, 850, 425, 1276, 638, 319, 958, 479, 1438, 719, 2158, 1079, 3238, 1619, 4858, 2429, 7288, 3644, 1822, 911, 2734, 1367, 4102, 2051, 6154, 3077, 9232, 4616, 2308, 1154, 577, 1732, 866, 433, 1300, 650, 325, 976, 488, 244, 122, 61, 184, 92, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]

Try to find a positive integer that does not eventually arrive at 1.
If you do, you’ll be famous (in the math community).