4. Functions

So far you have being using existing functions like list and type, but how about defining your own functions? Turns out that’s very easy with Python:

In [1]:
def addmult(x, y):
    adding = x + y
    multiplying = x * y
    return multiplying / adding

z = addmult(10.2, 30.0)
z
Out[1]:
7.611940298507462

That’s it, but just notice the spacing after the first line of the function. That’s the way Python functions (and as we’ll see, conditionals and loops) works: using indentation. A single whitespace or tab is enough, however, the most common usage is to have 4 whitespace in Python scripts.

4.1. Return value

Functions in Python can either return you “something" like the one above, or just return “nothing":

In [2]:
def print_and_return(x, y):
    adding = x + y
    multiplying = x * y
    print(multiplying)
    return

print_and_return(10.2, 30.0)
306.0

In the above case, you actually didn’t need the return, statement; once a function goes to its last line (i.e.: indentation decreases), it will return automatically:

In [3]:
def print_and_return(x, y):
    adding = x + y
    multiplying = x * y
    print(multiplying)

print_and_return(10.2, 30.0)
306.0

But, you could use return to make the function return immediately:

In [4]:
def print_and_return():
    print("This will be printed")
    return
    print("This will never be printed")

print_and_return()
This will be printed

This will prove itself useful together with conditionals in the next section.

4.1.1. An optional lookahead

In case of a function returning “nothing", you actually get something: a None object which happens to have Nonetype type:

In [5]:
def print_and_return(x, y):
    adding = x + y
    multiplying = x * y
    print(multiplying)

somevar = print_and_return(10.2, 30.0)
somevar is None
somevar
type(somevar)
306.0
Out[5]:
NoneType

4.1.2. Exercise

What’s wrong with the code bellow, why does the doesn’t z equals 60.0?:

In [6]:
def mult(x, y):
    multiplying = x * y
    multiplying

z = mult(2.0, 30.0)
z

4.2. Variable Scope

Here there’s three points to make, first that variables defined inside a function only exist within the scope of the function, so the code below:

def addmult(x, y):
    adding = x + y
    ddf
    multiplying = x * y
    return multiplying / adding

ddf = 342
addmult(10.2, 30.0)
adding

Will give you an error message:

NameError: name 'adding' is not defined

Second, that once you declare a variable inside a function it will not overwrite a variable defined outside of it which happens to have the same name, so:

In [7]:
def somefunc():
    somevar = 421
    print("Value inside somefunc()", somevar)
    return

somevar = 123
somefunc()
print("Value outside somefunc()", somevar)
Value inside somefunc() 421
Value outside somefunc() 123

Third, if you did not defined the variable inside the function, but it does exists outsize of it, then Python will use it, so:

In [8]:
def somefunc():
    print("Value inside somefunc()", something)
    return

something = 482
somefunc()
print("Value outside somefunc()", something)
Value inside somefunc() 482
Value outside somefunc() 482

So here’s a summary of it: when you ask Python to get you a variable inside a function, it will first attempt to get the one defined inside the function and then if not found, it will try outside the function.

If you ask it to set a variable, it will always set it on local scope of the function (it will not overwrite a variable defined outsize with the same name).

4.3. Named arguments and default values

To make things easier, Python also accepts you to pass the arguments of a function by name:

In [9]:
def somefunc(x, y, z):
    adding = 2 * x + y + z
    return adding * z

somefunc(x=10.2, y=30.0, z=3.1)
somefunc(y=30.0, z=3.1, x=10.2)
somefunc(10.2, y=30.0, z=3.1)
somefunc(10.2, z=3.1, y=30.0)
somefunc(10.2, y=3.1, z=30.0)
Out[9]:
1605.0

You can also provide some default value for an argument (effectively making it optional):

In [10]:
def somefunc(x, y, z=1):
    adding = 2 * x + y + z
    return adding * z

somefunc(10.2, 30.0)
somefunc(10.2, 30.0, 1)
somefunc(y=30.0, x=10.2)

somefunc(y=30.0, x=10.2, z=1.4)
somefunc(10.2, 30.0, 1.4)
Out[10]:
72.52

4.4. Lambda and function redefinitions

In Python, a function can also be seems as a object or as variable like any other else (with the special property of being callable), and as such, you can redefine it as usual:

In [11]:
def somefunc(x, y):
    adding = 2 * x + y
    return adding * 4

somefunc(10.2, 30.0)

somefunc = "Something else"

def somefunc(x):
    return x*2

somefunc(43.2)
Out[11]:
86.4

You can also create a function in a single line using the lambda syntax:

In [12]:
somefunc = lambda x, y: 2 * x + y

somefunc(10.2, 30.0)
Out[12]:
50.4

This will prove itself useful in the future…