Python functions

Python Functions: Making Your Code Reusable

If you are getting started with Python one of the topics you will encounter soon are functions. Here is how you can start using them.

Python functions allow to make your code more readable and reusable. A function is a block of code that performs a specific operation or returns a specific result. Once you define a function you can simply call it over and over in your code without having to rewrite that code again.

We will start by looking at how to define a function and then section after section we will keep building on the concepts you will learn.

By the end of this tutorial you will know a lot about functions! 😀

What Are Python Functions?

The concept of function in Python is the same as in many other programming languages.

A function allows to organise code in modular blocks and it makes it reusable. The more your code grows the more difficult it can get to manage it if you don’t use functions.

Below you can see the full syntax of a function:

def function_name(parameters):
    """docstring"""
    function_body

The components used to define a Python function are:

  • header: this is made of def keyword, used to start the definition the function, function name, parameters enclosed within parentheses and the colon symbol. Parameters are optional, this means that you can define a function that doesn’t accept any parameters.
  • docstring: provides documentation about the function.
  • body: this is a list of Python statements and it can end with an optional return statement.

Let’s see an example of function that accepts a single parameter and prints a message that depends on the value passed when calling the function.

def say_hello(name):
    print("Hello " + name)

The name of the function is say_hello and it accepts one parameter called name.

The function executes a single print statement that concatenates the word “Hello” with the value of the parameter passed to the function.

To call a Python function you specify the name of the function followed by parentheses. Within parentheses you provide any values to be passed to the function (these are called arguments).

say_hello("Codefather")

[output]
Hello Codefather

Later in this tutorial I will explain the difference between parameters and arguments. It’s a topic that can create confusion when you start working with functions.

How Does a Python Function Work?

We have seen how to define a function and how to call it.

But how does a function work exactly when it comes to the execution flow of a program?

The following diagram shows how…

How does a Python function work?

The Python program is executed line by line until the call to the function is encountered, in this case say_hello().

At that point the execution of the main Python program jumps to the function and goes through all the lines of code in the function until the function ends or a return statement is found.

Then the execution of the program continues from the next line after the function call and it continues until the last line of the main program.

How to Define a Python Function with Multiple Lines

In the previous example we have defined a function whose body has a single line of code.

A function with multiple lines of code can be defined but it’s important that every line in the body of the function has the same indentation. If the indentation of lines within a function is not the same the Python interpreter raises a syntax error.

Let’s update the previous function and add another couple of lines to also print today’s date using the datetime module.

from datetime import date

def say_hello(name):
    today = str(date.today())
    message = "Hello " + name + ". Today is " + today
    print(message)

The first line of the function gets today’s date and converts it into a string. Then the date is concatenated with the rest of the string.

In the second line we create a message that we print in the third line.

The function prints the following message when you call it.

Hello Codefather. Today is 2021-07-31

If you forget to convert today’s date into a string you will get the following TypeError exception:

Traceback (most recent call last):
  File "functions.py", line 9, in <module>
    say_hello("Codefather")
  File "functions.py", line 5, in say_hello
    message = "Hello " + name + ". Today is " + today
TypeError: can only concatenate str (not "datetime.date") to str

Notice that the three lines in our function follow the same indentation.

Let’s modify one of the lines in the function to use an incorrect indentation.

def say_hello(name):
    today = str(date.today())
message = "Hello " + name + ". Today is " + today
    print(message)

And see what happens…

  File "functions.py", line 6
    print(message)
    ^
IndentationError: unexpected indent

The Python interpreter raises an IndentationError exception.

What is the Return Statement in a Python Function?

In the function we have seen so far the function gets called and prints a message.

The most common approach when using a function is for the function to return one or more values to the caller (the line of code where the function is called).

Here is what I mean…

I want to create a program that calculates the sum of two numbers. Without using a function I could write the following code:

number1 = 10
number2 = 15
result = number1 + number2
print("The sum of the two numbers is " + str(result))

What if we want to write a function that we can then reuse in the future when we want to calculate the sum of two numbers?

def calculate_sum(a, b):
    result = a + b
    return str(result)

This function:

  • takes two parameters a and b.
  • calculates the sum of the two parameters.
  • uses the return statement to return the value of the variable result converted to a string using the str() function.

This allows us to use the value returned by the function in the main program.

number1 = 10
number2 = 15
print("The sum of the two numbers is " + calculate_sum(number1, number2))

Can you see how this time in the print statement we specify the call to the function?

We can do that because the function returns the sum through the return statement.

What Does a Python Function Return if No Return Statement is Present?

A Python function in which a return statement is not present returns None.

Let’s confirm it…

from datetime import date

def say_hello(name):
    today = str(date.today())
    message = "Hello " + name + ". Today is " + today
    print(message)

Notice that this function doesn’t have a return statement.

Now, store the value returned by the function into a variable called returned_value.

>>> returned_value = say_hello("Codefather")
Hello Codefather. Today is 2021-07-31
>>> print(returned_value)
None

This confirms that the value returned by the function is None.

What Are the Two Main Types of Python Functions?

The are two main types of functions in Python:

  • Built-in functions: they are built-in in Python and hence they are available immediately in your Python installation. Some examples of Python built-in functions are input(), isinstance(), len(), list(), print(), sum(), zip().
  • User-defined functions: they are custom functions that users create to solve specific problems that are not solved by built-in functions.

We have already seen how to create a user-defined function and we will go through more examples later on.

In the next section we will see some examples of built-in functions.

How Many Python Built-in Functions Are Available?

The latest version of Python 3.9 has 69 built-in functions. This number might change in future versions of Python.

Let’s take some built-in functions and see how you can use them.

Those are just some examples and they don’t represent the only thing that these functions can do.

Execute these examples on your Python shell to do a bit of practice with Python.

abs(): calculate the absolute value of a number

>>> print(abs(-10))
10

dict(): create an empty dictionary

>>> values = dict()
>>> print(values)
{}

float(): convert an integer into a floating point number

>>> print(float(10))
10.0

input(): take an input from the user

>>> number = input("Insert a number: ")
Insert a number: 25
>>> print(number)
25
>>> print(type(number))
<class 'str'>

I have created a tutorial if you want to know more about the input function.

int(): convert a string into an integer

>>> print(int("23"))
23
>>> print(type(int("23")))
<class 'int'>

isinstance(): check if an object is of a specific type

>>> number = 23
>>> isinstance(number, int)
True
>>> isinstance(number, str)
False
>>> isinstance(number, float)
False

The isinstance() function returns a boolean. The value of a boolean can be either True or False.

len(): calculate the size of a list

>>> animals = ['tiger', 'lion', 'giraffe']
>>> print(len(animals))
3

list(): convert a set into a list

>>> numbers = {1, 2, 3, 4}
>>> print(list(numbers))
[1, 2, 3, 4]
>>> print(type(list(numbers)))
<class 'list'>

max(): calculate the maximum value in a list

>>> numbers = [1, 2, 3, 4]
>>> print(max(numbers))
4

set(): convert a list into a set

>>> animals = ['tiger', 'lion', 'giraffe', 'lion']
>>> print(animals)
['tiger', 'lion', 'giraffe', 'lion']
>>> print(set(animals))
{'giraffe', 'tiger', 'lion'}

Notice that the list contains four elements while the set contains three elements because a set cannot contain duplicates.

tuple(): convert a list into a tuple

>>> animals = ['tiger', 'lion', 'giraffe', 'lion']
>>> print(tuple(animals))
('tiger', 'lion', 'giraffe', 'lion')

zip(): merge two tuples

>>> cities = ('Rome', 'Warsaw')
>>> countries = ('Italy', 'Poland')
>>> print(zip(cities, countries))
<zip object at 0x7f8058083640>
>>> for value in zip(cities, countries):
...     print(value)
... 
('Rome', 'Italy')
('Warsaw', 'Poland')

Here we have used a Python for loop to go through the output returned by the zip function.

Local Variable Scope in a Function

The scope of a variable defined in a Python function is local.

What does it mean exactly?

If you declare a variable in a Python function that variable is not visible outside of the function.

This can be an abstract concept so let’s make it clear with a simple example.

from datetime import date

def say_hello(name):
    today = str(date.today())
    message = "Hello " + name + ". Today is " + today
    print("Inside the function: " + message)


message = "Hello Universe!"
print("Before function call: " + message)
say_hello("Codefather")
print("After function call: " + message)

I have updated the third line of the say_hello() function to specify the fact that this message is printed inside the function.

Then I have declared another variable with the same name (message) outside of the function.

Execute this code and see what happens…

Before function call: Hello Universe!
Inside the function: Hello Codefather. Today is 2021-07-31
After function call: Hello Universe!

As you can see the value of the variable message outside of the function doesn’t change after the function call.

That’s because the variable message defined in the function is only visible in the function.

Now, try to comment out the second line of the function.

def say_hello(name):
    today = str(date.today())
    #message = "Hello " + name + ". Today is " + today
    print("Inside the function: " + message)

What do you think will happen when you call the function?

Are we going to see an error because the variable message is not defined in the function?

Let’s find out…

Before function call: Hello Universe!
Inside the function: Hello Universe!
After function call: Hello Universe!

Interesting, the function has used the variable message defined outside of the function.

So…

Any variables defined outside of a Python function are also visible inside the function.

Difference Between Parameter and Argument in Python

Previously in this tutorial we have mentioned two terms: parameter and argument.

As soon as you will start working with functions it’s likely that you will ask yourself what is the difference between parameters and arguments?

This is a very common questions and it often causes confusion when you are getting started with coding.

Here is a definition of the two that will make things clear…

With the word parameters you refer to the values that are present in the header of a function within parentheses. You can say that a function accepts certain parameters. Arguments are the values passed when calling a function. So arguments give values to function parameters.

Let’s take the following code as an example:

def calculate_sum(a, b):
    result = a + b
    return str(result)

number1 = 10
number2 = 15
print("The sum of the two numbers is " + calculate_sum(number1, number2))

Which ones are parameters and which ones are arguments?

  • The parameters are a and b (they are present in the header of the function).
  • The arguments are number1 and number2 (they are passed to the function when it’s called).
  • The value of number1 is assigned to the parameter a and the value of number2 is assigned to the parameter b).

The order of arguments in a function call matches the order of parameters in the function definition.

Passing Multiple Arguments to a Function

You can pass multiple arguments to a Python function only if the function accepts the same number of parameters.

For example, let’s take the calculate_sum function defined before:

def calculate_sum(a, b):
    result = a + b
    return str(result)

And pass three arguments to it…

number1 = 10
number2 = 15
number3 = 23
print("The sum of the two numbers is " + calculate_sum(number1, number2, number3))

The Python interpreter raises a TypeError exception because the function takes two positional arguments but 3 were passed to it.

Traceback (most recent call last):
  File "functions.py", line 22, in <module>
    print("The sum of the two numbers is " + calculate_sum(number1, number2, number3))
TypeError: calculate_sum() takes 2 positional arguments but 3 were given

To address this error we have to add another parameter to the function.

def calculate_sum(a, b, c):
    result = a + b + c
    return str(result)

Execute the program now and confirm that the exception is not raised anymore and that you get the correct result.

The sum of the two numbers is 48

One thing that is becoming obvious with our calculate_sum() function is that it’s not very flexible because it can only be used with a fixed amount of numbers.

What if you want to change the function to calculate the sum for 4, 5, 6…. numbers without having to change the function?

You can do it by using Python *args.

Passing Optional Arguments to a Python Function

In some cases you might want to make some function parameters optional.

How can you do that?

Let’s say we want to modify the calculate_sum function to make the third parameter optional.

You can use the following syntax:

def calculate_sum(a, b, c=0):
    result = a + b + c
    return str(result)

If you don’t pass the third argument its value is automatically set to zero.

Test the function with two and three arguments in the function call to make sure it works in both cases.

Pass two arguments to the function

>>> print(calculate_sum(1, 2))
3

Pass three arguments to the function

>>> print(calculate_sum(1, 2, 3))
6

How to Return Multiple Values From a Python Function

A Python function can also return multiple values by using the return statement. The values returned by the function are comma separated and they are returned as a tuple.

Update the calculate_sum function to also calculate the difference of the two numbers and to return both.

def calculate_sum_and_difference(a, b, c=0):
    numbers_sum = a + b + c
    numbers_difference = a - b - c
    return str(numbers_sum), str(numbers_difference)

Call the function and verify that the two values are returned inside a tuple.

>>> print(calculate_sum_and_difference(1, 2, 3))
('6', '-4')
>>> print(type(calculate_sum_and_difference(1, 2, 3)))
<class 'tuple'>

To access individual items in the tuple you can use square brackets.

>>> print(calculate_sum_and_difference(1, 2, 3)[0])
6
>>> print(calculate_sum_and_difference(1, 2, 3)[1])
-4

What is the Docstring of a Python Function?

Documenting your code is always a good practice.

While you are writing your code you might know what the function is supposed to do but if you read your code months later you might be surprised…

…you might even wonder if you were the one who wrote that code 🙂

Having a function docstring in place allows you and anyone else who reads your code to understand immediately what a function does without having to go through it line by line.

Define a function that calculates the sum of two numbers and add a docstring immediately after the header of the function:

>>> def calculate_sum(x, y):
...     """
...     The function calculate_sum calculates the sum of two numbers
...     """
...     return x + y

The triple quotes allow to extend the docstring to multiple lines.

To print the docstring of a function you can use the __doc__ attribute of the function.

>>> print(calculate_sum.__doc__)

	The function calculate_sum calculates the sum of two numbers
	
>>> 

How to Pass a List to a Python Function

It’s also possible to pass a list to a Python function.

Modify the function calculate_sum_and_difference to accept a list of numbers instead of individual numbers.

def calculate_sum_and_difference(numbers):
    numbers_sum = numbers[0] + numbers[1] + numbers[2]
    numbers_difference = numbers[0] - numbers[1] - numbers[2]
    return str(numbers_sum), str(numbers_difference)

When you call the function remember to pass a list of numbers.

>>> print(calculate_sum_and_difference([1, 2, 3]))
('6', '-4')

How to Pass a Tuple to a Python Function

You can pass a tuple to a Python function.

Modify the function calculate_sum_and_difference to accept a tuple of numbers.

Actually…

The function remains identical to the version in which we passed a list.

def calculate_sum_and_difference(numbers):
    numbers_sum = numbers[0] + numbers[1] + numbers[2]
    numbers_difference = numbers[0] - numbers[1] - numbers[2]
    return str(numbers_sum), str(numbers_difference)

Let’s pass a tuple of numbers to it.

>>> print(calculate_sum_and_difference((1, 2, 3)))
('6', '-4')

Note: the only difference compared to the previous example is that this time we have passed a tuple to the function by replacing square brackets with parenteses.

How to Pass a Dictionary to a Python Function

Let’s try to pass the following dictionary to the calculate_sum_and_difference function.

numbers = {'a': 1, 'b': 2, 'c': 3}

We have to modify the function slightly to read the values in the dictionary mapped to each key:

def calculate_sum_and_difference(numbers):
    numbers_sum = numbers['a'] + numbers['b'] + numbers['c']
    numbers_difference = numbers['a'] - numbers['b'] - numbers['c']
    return str(numbers_sum), str(numbers_difference)

And the output is…

>>> print(calculate_sum_and_difference(numbers))
('6', '-4')

It worked! 😀

Conclusion

Wow, I initially wanted to write a quick tutorial about Python functions…

…but then I realised there were few more things I wanted to show you to make sure you really get how functions work.

I hope you have found this tutorial useful.

If you have any questions feel free to email me at hello@codefather.tech.

Happy coding! 😀

Share knowledge with your friends!

Leave a Reply

Your email address will not be published. Required fields are marked *