4
By the end of this chapter, you will be able to:
This lesson introduces functions in Python. We look at the various types of functions and define our own.
In the previous chapter, we covered the following topics:
We will continue to build on this knowledge by implementing what we have learned, to build functions in Python.
Functions are an integral part of the Python programming language, and a lot of languages, really. Throughout this book, you have already encountered some built-in functions, especially when dealing with certain data structures.
Functions are an easy way to group a few lines of code that implement a functionality together. This is especially useful if the code in question will be used several times in different parts of your program. You may want to use functions to abstract away some complex code that you need in your programs. You can think of functions as mini-programs within your bigger program that implement specific tasks.
It is important to remember that while it is tempting to tuck a lot of functionality into a single function, it is better to write functions that only perform one specific task. This makes it easier to modularize your code, and, in the long run, it is more maintainable and easier to debug.
Functions may take optional inputs to work with and may optionally return a value or values.
The three main types of functions in Python are as follows:
The Python interpreter has a number of built-in functions and types that are always available. These are called built-in functions, and they can be used anywhere in your code, without the need of any importation.
Some of the built-in functions that we have already encountered in this book are as follows:
For example, we recently used the built-in print() function to output results; the following is another simple demonstration:
print("Hello world")
This results in the following:
Hello world
As the name suggests, these are functions that are written by the user, to aid them in achieving a specific goal. The main use of functions is to help us organize our programs into logical fragments that work together to solve a specific part of our problem.
The syntax of a Python function looks like this:
def function_name( parameter_one, parameter_two, parameter_n ):
# Logic goes here
return
To define a function, we can use the following steps:
A user-defined function must have a name. You can give it any name that you like, and it is a good practice to make the name as descriptive of the task that the function achieves as possible. For example, if you are writing a function that calculates the monthly average rainfall from a list of values, it is better to name the function calculate_monthly_average_rainfall() than calculate(). Remember, code is written to be read by humans, not computers. Make it easy for other humans to immediately understand what a function does, just by looking at the name:
def calculate_monthly_average_rainfall(list_of_annual_values):
# Loop over list and calculate average here
return average
Parameters are the information that needs to be passed to the function, in order for it to do its work. Parameters are optional, and they are separated by commas and placed between parentheses after the function name. A function can have any number of parameters, and there is really no limit to this.
Calling a function means executing the logic that is defined inside of the function. This can be done from the Python interactive prompt, or from within some other part of your code. Functions are often called from other functions.
If we were to call the function that we defined earlier (the one that calculates the monthly rainfall average), we would just do something like this:
annual_values = []
calculate_monthly_average_rainfall(annual_values)
Note that the names of the arguments that we pass when we are calling the function in this instance do not have to match the parameter names that the function expects. What is important is that no matter what you pass to the function when calling it, the function will refer to this parameter as list_of_annual_values internally.
This transitions us smoothly to our next sub-topic: global and local variables.
Variables that are defined inside of a function body are called local variables, as they are only accessible inside the function. They are said to have a local scope.
Variables that are defined outside of a function body are called global variables, as they are accessible both outside and inside of the functions. They are said to have a global scope because of this.
In this exercise, we will define global and local variables. We will also demonstrate the difference between global and local variables:
number = 5
def summation(first, second):
total = first + second + number
return total
summation(10, 20)
print("The first number we initialised was " + str(number))
print("The total after summation is " + str(total))
Note the use of the built-in function, str(), which returns the string version of an object.
The final code is as follows:
# Initialise global variable "number" to 5
number = 5
"""
Define function "summation" that takes two parameters
Note that the function accesses the global variable "number"
"""
def summation(first, second):
# Add the parameters and global number together
total = first + second + number
# Return result
return total
# Call the "summation" function with two parameters as expected
summation(10, 20)
# Print out the initial value of "number"
print("The first number we initialised was " + str(number))
# Try to access the local variable "total"
print("The total after summation is " + str(total))
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
The first number we initialised was 5
Traceback (most recent call last):
File "main.py", line 21, in <module>
print("The total after summation is " + str(total))
NameError: name 'total' is not defined
As you can see, this results in an error, because we are trying to access the local variable total from the global scope. This is just to demonstrate that we cannot access local variables globally.
# Initialise global variable "number" to 5
number = 5
"""
Define function "summation" that takes two parameters
Note that the function accesses the global variable "number"
"""
def summation(first, second):
# Add the parameters and global number together
total = first + second + number
# Return result
return total
# Call the "summation" function with two parameters as excepted
# Assign the result of "summation" to the variable "outer_total"
outer_total = summation(10, 20)
# Print out the initial value of "number"
print("The first number we initialised was " + str(number))
# Try to access the local variable "total"
print("The total after summation is " + str(outer_total))
Notice that we are now assigning the result of the summation function to the outer_total variable.
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
The first number we initialised was 5
The total after summation is 35
The return statement in Python is used within functions, to actually return something to the caller of the function. Without a return statement, every function will return None.
Consider the following function:
def summation(first, second):
total = first + second
print("The total is " + str(total))
summation(10, 20)
The output of this code is:
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
The total is 30
Note that the summation function, in this case, does not have a return statement. As mentioned previously, a return statement is not necessary for all functions. The purpose of this function in particular is to print out the total, and in this case, it is not necessary to return anything, as the printing can be done within the function.
However, a return statement is required if you need to use the result of calling a function for any further processing in your code. Consider the following variation:
def summation(first, second):
total = first + second
return total
outer_total = summation(10, 20) * 2
print("Double the total is " + str(outer_total))
In this variation, we can see that the summation function returns the sum of the passed-in values. This returned value is then multiplied by two and assigned to the outer_total variable. This way, the function has, in essence, abstracted away the operation of summing the two numbers.
Of course, this is just a rudimentary example, and with this knowledge, you can begin to build more complex functions and programs.
Most other programming languages (for example, Java and C++) require a special function, called main(), which tells the operating system what code to execute when a program is invoked. This is not necessary in Python, but you will find that it is a good and logical way to structure a program.
Before the Python interpreter executes our program, it defines a few special variables. One of them is __name__, and it will automatically be set to __main__ if our program will be executed by itself, in a standalone fashion.
However, if our program will be imported by another program, then __name__ will be set to the name of that other program. We can easily determine whether the program is standalone or is being used by another program as an import. Based on that, we can decide to either execute or exclude some of the code in a program.
The following is an example that uses the main() function:
def summation(first, second):
total = first + second
return total
def main():
outer_total = summation(10, 20) * 2
print("Double the total is " + str(outer_total))
if __name__ == "__main__":
main()
Without the if __name_ == __main__ check and declaration, our script would still be executable. All we would have to do is declare or call our summation() function.
In Python, there is nothing special about the name main. We could have called this function anything that we wanted. We chose main to be consistent with some of the other languages.
As mentioned earlier, parameters are the information that need to be passed to the function for it to do its work. Although parameters are also commonly referred to as arguments, arguments are thought of more as the actual values or references assigned to the parameter variables when a function is called at runtime. In simpler terms, arguments are to functions as ingredients are to a recipe.
Python supports several types of arguments; namely:
Required arguments are the types of arguments that have to be present when calling a function. These types of arguments also need to be in the correct order for the function to work as expected.
Consider the following code snippet:
def division(first, second):
return first/second
You have to pass the arguments first and second for the function to work. You also have to pass the arguments in the correct order, as switching them will yield completely different results.
You would then call the function like this:
quotient = division(10, 2)
The result, as expected, would be as follows:
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
5.0
If it is necessary that you call all of the parameters in the right order, you can use keyword arguments in your function call. You can use these to identify the arguments by their parameter names. Let's consider the previous example to make this a bit clearer:
def division(first, second):
return first/second
quotient = division(second=2, first=10)
print(quotient)
As you can see, we have intentionally passed arguments in the wrong order by swapping their positions. The difference here is that we used the names of the arguments when passing them. By doing this, we corrected our mistake, and the function will receive its parameters in the right order and give us the correct (and expected) output, which is as follows:
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
5.0
Keyword arguments are very powerful, and they ensure that no matter which order we pass arguments in, the function will always know which argument goes where.
Default arguments are those that take a default value if no argument value is passed during the function call. You can assign this default value with the assignment operator, =, just like in the following example:
def division(first, second=2):
return first/second
quotient = division(10)
print(quotient)
The output for this example is the same as that of the previous examples.
Note that even if the argument named second has a default value, you can still pass a value to it, and this passed value will override the default value. This means that the function will promptly ignore the default value and use whatever value you passed to it.
The following is an example with the default argument where a value is passed:
def division(first, second=2):
return first/second
quotient = division(10, 5)
print(quotient)
As expected, the output of this snippet is:
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
2.0
It might so happen that you want to allow a function to receive any number of variables, and then process them. Wouldn't it be convenient if you could pass a variable number of arguments to this function? Well, you're in luck! This is possible in Python by using the special * (asterisk) syntax.
The following is an example of using *args:
def addition(*args):
total = 0
for i in args:
total += i
return total
answer = addition(20, 10, 5, 1)
print(answer)
Note that you don't have to name the variable *args. You could have named it *numbers, and the function would have worked just as well.
Write a function that receives n number of arguments; using a continue statement, skip integers and print out all other values.
The steps are as follows:
The output should be as follows:
>>> print_arguments(2, 3.4, "s", 1.0)
3.4
s
1.0
Solution for this activity can be found at page 285.
Anonymous functions in Python are also called lambda functions. This is because they use the keyword lambda in their definition.
Anonymous functions are so called because, unlike all of the other functions that we have looked at up to this point, they do not require to be named in their definition. The functions are usually throwaway, meaning that they are only required where they are defined, and are not to be called in other parts of the codebase.
The syntax of an anonymous function is as follows:
lambda argument_list: expression
The argument list consists of a comma-separated list of arguments, and the expression is an arithmetic expression that uses these arguments. You can assign the function to a variable to give it a name.
Let's look at a practical application of a lambda function. Suppose that you want to simply sum up two numbers in a function. There is no need to define a whole user-defined function for this if you are only going to use it once:
answer = lambda first, second : first + second
print(answer(6, 9))
Here, we have defined a lambda function that takes two parameters (first and second) and adds them up. We have then assigned the function to the answer variable, so that we have a way to refer to it.
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
15
The true power of anonymous functions can be seen when they are used in combination with the map(), reduce(), or filter() functions.
The syntax of a map() function is as follows:
map(func, iterable)
The first argument, func, is the name of a function, and the second, iterable, is a sequence (for example, a list). map() applies the func function to all of the elements of the iterable sequence. It returns a new list, with the elements changed by func.
Let's suppose that you have the following list, and want to generate a new list with the squares of every item in the list:
numbers = [2, 4, 6, 8, 10]
One way to implement this would be:
numbers = [2, 4, 6, 8, 10]
squared = []
for num in numbers:
squared.append(num**2)
The for loop, in this case, can be replaced with a lambda function that serves the same purpose, like this:
lambda num: num ** 2
We can then use the map() function to apply this lambda function to each of the items in the list, in order to get their squares, like this:
squared = map(lambda num: num ** 2, numbers)
This will yield a map object, and, to cast this to a list, we use the list() function, like this:
squared = list(map(lambda num: num ** 2, numbers))
Our whole program then reduces to just three lines:
numbers = [2, 4, 6, 8, 10]
squared = list(map(lambda num: num ** 2, numbers))
print(squared)
The output of these lines is as follows:
Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
[4, 16, 36, 64, 100]
This definitely shows the versatility of lambda/anonymous functions, and their ability to make our code more concise.
Write a lambda function that takes in two numerical values and returns the first value, raised to the power of the second value:
The output should be as follows:
>>> print(answer(2, 4))
16
Solution for this activity can be found at page 285.
In this chapter, we learned about the various types of functions in Python, as well as their differences, syntax, and use cases. We covered how and where to apply the different types of functions, and how they can be used to help break your programs into smaller sub-programs that achieve a specific purpose. We also saw how the use of functions can help use reuse functionality in our code and avoid repeating the same blocks of code.
With this knowledge, you should be able to build all sorts of well-structured programs that will be easy to read and understand, and which will make optimal use of repetitive functionality.
In the next chapter, we will take a look at lists and tuples; it will be our first chapter regarding the various data structures that Python offers.