Python Course #16: Functions
Post
Cancel

# Python Course #16: Functions

Up until now you have used a lot of functions already, most prominently the print(...) function. Now it is time to write your own functions in Python.

## What is a function in Programming?

A function is a piece of code that is responsible for carrying out a task. Functions encapsulate several lines of code into one line and make them accessible througout an entire program. Thereby they help you to use your code several times without reapting yourself. This is especially helpful when a function needs to be changed in the future and there is only one place this change has to be applied to, the function itself. Functions can also drastically improve the readability of your code by splitting a large and complex piece of of code into smaller steps encapsulated by functions.

Functions can be seen as a black box where data is passed to the function and a result is returned after the function finished its execution. In general a user of a function is not interested in how a functions does its task, they are only interested that it does the task.

## Declaring a Function in Python

Writing your own function in Python is straightforward. A new function is initialized with the keyword def followed by the function name and parenthesis holding the parameters with a colon : at the end. This is also called the function’s signature. Indented under the signature is the code of a function also called the function body. The code can include several return statements that end the function and return a value to the caller:

1 2 def FUNCTION_NAME([PARAMETERS, ...]): [return VALUE] 

Functions are usually declared at the beginning of your code above the if __name__ == "__main__": part. Even though, Python allows to declare functions inside functions it should not be used if it is not necessary, because functions inside functions can lead to bugs that are hard to uncover.

The first function you will write adds two variables together and returns the result:

1 2 3 4 5 6 def add(x, y): return x+y if __name__ == "__main__": result = add(23, 42) print(result) 

In the code above the function add has two parameters x and y. Those two parameters are only available inside of the function. You can have variables with the same name outside of the add function but the function can’t access those neither do the values assigned to those variables influence the values inside of the function.

## Python Function return

The add function only consists of one line return x+y. The return keyword ends the functions and returns the result of the expression after it to the caller. In line 5 you can see how the function is called using it’s name and two arguments for the parameters x and y.

A function can have multiple return statements. The following code returns the maximum of two values:

1 2 3 4 5 6 7 8 def maximum(a, b): if a > b: return a return b if __name__ == "__main__": result = maximum(23, 42) print(result) 

As the return statement ends the function an else after the if is not necessary.

## Python Functions without return

A Python function however, does not need a return. As you learned in the article about Python’s pass by assignment a function can change the value of an argument when it is passed by reference which is the case for all non primitive data types:

1 2 3 4 5 6 7 8 def double(l): l.extend(l) if __name__ == "__main__": numbers = [1,2,3] double(numbers) double(numbers) print(numbers) 

The double function in the code above extends the list l with l and thereby “doubles” the list. Because the double function is called two times the list numbers is quadrupled. The return value of a function that does not end with a return is None.

## Python pass and … (Ellipsis)

When you start to structure a program into different functions you often won’t implement the function right away and the function stay’s empty. Empty functions however, are not allowed in Python’s syntax and because of this the keyword pass and the ellipsis ... exist:

1 2 def not_implemented(x): pass 
1 2 def not_implemented(x): ... 

Both pass and ... do nothing but fill a function with code and indicate that there is some work to do in the future. Which one you choose is a matter of preference.

## Python Function Multiple Return Values

In contrast to other programming languages Python functions allow you to return multiple values at once. The function quadratic_formula provides the solution to a quadratic equation of the form $$ax^2 + bx + c = 0$$. And because of the nature of quadratic equations there can be two, one or no solution:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import math def quadratic_formula(a,b,c): square_root_arg = b**2 - 4*a*c if square_root_arg < 0: return (None, None) x_1 = (-b + math.sqrt(b**2 - 4*a*c))/(2*a) x_2 = (-b - math.sqrt(b**2 - 4*a*c))/(2*a) return (x_1, x_2) if __name__ == "__main__": x_1, x_2 = quadratic_formula(2, 0, 0) print(x_1, x_2) x_1, x_2 = quadratic_formula(3, 9, 6) print(x_1, x_2) x_1, x_2 = quadratic_formula(1, 3, 4) print(x_1, x_2) 

To return two or more values from a function. The return values have to be bundled as a tuple. The caller then needs to comma seperate the variables that will store the return values in the same order as in the returned tuple. If a function returns several values, but you are not interested in all of those it is common to name the variable that stores the values that are of no interest _.

## Python Named Function Parameters

When you declare a function with a lot of parameters it can become quite confusing for the caller to keep track of the parameter order. To prevent mixing up the parameter order the caller can specify the order themselves:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import math def quadratic_formula(a,b,c): square_root_arg = b**2 - 4*a*c if square_root_arg < 0: return (None, None) x_1 = (-b + math.sqrt(b**2 - 4*a*c))/(2*a) x_2 = (-b - math.sqrt(b**2 - 4*a*c))/(2*a) return (x_1, x_2) if __name__ == "__main__": x_1, x_2 = quadratic_formula(c=6, a=3, b=9) print(x_1, x_2) 

In line 15 of the code above the function quadratic_formula(...) is called using named parameters. For each argument corresponding parameter is stated with an equal sign. With named parameters an arbitrary parameter is possible and makes your code a lot more readable.

You can also mix named and not named parameters. To do so you start with stating the not named parameters in the parameter order as soon as you use a named parameter all of the following parameters must be named as well:

1 2 3 4 5 def func(one, two, three, four, five): pass if __name__ == "__main__": func(1, 2,three=3, five=5, four=4) 

## Python Function Default Arguments

In some cases it is helpful to set a default argument for a function. This makes calling the function easier because some arguments can be left out and it helps with the reliability of the code when there are default arguments that make sure the function gets a valid argument:

1 2 3 4 5 6 7 8 9 10 def get_student_dict(firstname, lastname, semester=1): return { 'firstname': firstname, 'lastname': lastname, 'semester': semester } if __name__ == "__main__": print(get_student_dict("Maria", "Hill", 3)) print(get_student_dict("Laura", "Barton")) 

In the code above a new dictionary is created that includes the first- and lastname of a student together with the semester the student is currently in. The minimal valid semester a student can be in is 1. In the function signature of get_student_dict(...) the last parameter semester gets a default argument assigned to it using an equal sign followed by the default argument. The caller can now call this function without passing an argument for semester and the default value will be used instead.

## Python Function Arbitrary Arguments *args

Python also allows you to pass an arbitrary number of arguments to a function when adding an asterisk * infront of the parameter (often named args):

1 2 3 4 5 6 def arbitrary_args(*args): for arg in args: print(arg) if __name__ == "__main__": arbitrary_args("one", "two", "three", "four") 

In the code above the parameter args can hold as many arguments as you like. args is actually a tuple in which you can access individual elements via an iterator or with the bracket-operator [].

## Python Function Keyword Arguments **kwargs

Instead of passing an arbitrary amount of arguments to a function and then accessing the elements in tuple you can also pass an arbitrary amount of arguments with a keyword by adding two asterisks ** in front of the parameter (often named kwargs):

1 2 3 4 5 6 def arbitrary_args(**kwargs): for k, v in kwargs.items(): print(k, "->", v) if __name__ == "__main__": arbitrary_args(one=1, two=2, three=3, four=4) 

The kwargs in the code above is a dictionary in which you can access key value pairs with an iterator or via the bracket-operator.