Functions

Functions in Python (and other languages in general) are a way to package reusable chunks of code. You define a function using the def keyword. They can be simple


In [1]:
def plus_one(x):
    return x + 1

In [2]:
plus_one(1)


Out[2]:
2

In [3]:
plus_one(2)


Out[3]:
3

or complex


In [4]:
def do_math(x):
    return (x * 2.)/(x - 1.)

In [5]:
do_math(2)


Out[5]:
4.0

In [6]:
do_math(42)


Out[6]:
2.048780487804878

You can call functions from within other functions.


In [7]:
def abra(s):
    return "Abra " + s

def alakazam(s):
    return abra(s) + " Alakazam"

alakazam("Kadabra")


Out[7]:
'Abra Kadabra Alakazam'

Functions can have lots of arguments/parameters


In [8]:
def all_the_params(a, b, c, d):
    return a + b + c + d

all_the_params(1, 2, 3, 4)


Out[8]:
10

or no arguments


In [9]:
def toop():
    return "toop"

toop()


Out[9]:
'toop'

Functions can take pretty much anything as arguments, including other functions.


In [10]:
def call_it_twice(fun):
    return fun() + " " + fun()

call_it_twice(toop)


Out[10]:
'toop toop'

Functions can also return functions


In [11]:
def print_it_twice(number):
    def x():
        return number + " " + number
    return x

a_fun = print_it_twice("Double")
a_fun


Out[11]:
<function __main__.x>

Here a_fun is a function which you can call like any other function


In [12]:
a_fun()


Out[12]:
'Double Double'

Default Values

You can give a function default values for its arguments.


In [13]:
def with_defaults(x, y = 2, z = 3):
    print(x, y, z)
    return x + y + z

In [14]:
with_defaults(1) # Using both default values.


(1, 2, 3)
Out[14]:
6

In [15]:
with_defaults(1, 1) # Using one default value.


(1, 1, 3)
Out[15]:
5

In [16]:
with_defaults(1, 1, 1) # Using no default values.


(1, 1, 1)
Out[16]:
3

If you wanted to change only z but not y you can used a keyword argument.


In [17]:
with_defaults(1, z = 4) # Use the default value for y but not z.


(1, 2, 4)
Out[17]:
7

This is useful for dealing with functions with lots of default values when you only want to change some of the defaults.

Recursions

Functions can also call themselves. This is known as recursion.


In [18]:
def deeper():
    return deeper()

deeper()


---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-18-57c4906432e3> in <module>()
      2     return deeper()
      3 
----> 4 deeper()

<ipython-input-18-57c4906432e3> in deeper()
      1 def deeper():
----> 2     return deeper()
      3 
      4 deeper()

... last 1 frames repeated, from the frame below ...

<ipython-input-18-57c4906432e3> in deeper()
      1 def deeper():
----> 2     return deeper()
      3 
      4 deeper()

RuntimeError: maximum recursion depth exceeded

Though unless your function stops calling itself you're going to have issues.


In [19]:
def sum_up_to(x):
    print(x)
    if x <= 0: return 0
    else: return x + sum_up_to(x - 1) 

sum_up_to(4)


4
3
2
1
0
Out[19]:
10

Function Gotchas

If you forget to include the return keyword your function will return None.


In [20]:
def no_return(x):
    x + x

a_thing = no_return(42)
print(a_thing)


None

If you forget to include () when calling a function


In [21]:
print(toop) # Incomplete


<function toop at 0x7f67f9f88e60>

you get back the function itself as opposed to the result of the function