Functions in Python

Python Functions – Complete Tutorial

In any programming language, the function is a reusable block of code that allows us to implement repetitive tasks in the code without code duplication. Functions allow you to write clean, organized, and manageable code. This Python functions tutorial covers Python functions, their syntax, arguments, return statements, Python function annotations, and many more.

Types of functions

In Python, functions are defined to perform a specific task. Several types of Functions can be used in Python, each with its capabilities. The first function type is the built-in function. For example, the ‘print’ function displays text on the screen, or the ‘input’ function allows the user to enter data into the program.

Functions can also be defined to reuse code, known as user-defined functions. User-defined functions can take arguments, which are values passed into the function to change its behavior. For example, a user-defined function could be written to calculate the area of a rectangle, and the width and height would be passed in as arguments.

Finally, there are also anonymous functions, which are Python functions that do not have a name. These functions are commonly used when they only need to be used once or are too complicated to be written as a single line of code.

In summary, several different types of functions can be used in Python, each with its purpose:

  • built-in functions
  • user-defined functions
  • anonymous functions

By understanding each type of function’s capabilities, programmers can write more efficiently and easier-to-understand programs.

Built-in functions available for you with Python distribution out of the box and allow you to perform different tasks:

  • Math operations
  • Type conversion
  • Managing iterators
  • Managing composite data types
  • Working with classes
  • Manage variables, references, and scope

Python developers declare any functions in their code are called user-defined functions, which are the primary focus of this article.

Function syntax

Here’s a syntax for defining Python function:

def <function_name>([parameters]):
    """optional docstring"""
    code_statement(s)
    [return [expression]]

Here’s a description of the most important parts of the function definition:

  • def – keyword used for defining the function name and optional parameters
  • <function_name> – the name of the function
  • [parameters] – optional comma-separated list of parameters that the function may need to accept
  • """optional docstring""" – optional documentation string of the function
  • code_statement(s) – one or more lines of code that implement the logic of the function
  • [return [expression]] – an optional statement that allows returning something from the function

All code_statement(s) are forming Python function body and should have the same level of indentation.

Simple Python function

Let’s create a simple function to illustrate the Python execution flow using the following Python program as an example:

def my_function():
    """This function prints a message"""
    message = '* Code executed during function call *'
    print(message)
print('Code executed before function call')
my_function()
print('Code executed after function call')
1. Functions in Python - Simple function execution

Now, let’s take a look at how Python processes this code:

Every time you call a function in your program, Python will execute the same piece of code from the function body.

Empty Python function

Sometimes, you may need to define an empty function, for example, not to forget to implement something later.

In that case, you can use a pass statement.

Such definition is usually called a function placeholder or a stub:

def my_function():
    pass
my_function()

The such definition allows you to call a function from your code, but nothing is going to happen:

2. Functions in Python - Placeholder

Function arguments

You need to use function arguments when you need to pass data into your function.

Let’s review all types of arguments one by one.

Positional arguments

The most common way to define arguments for a Python function is using positional arguments (or required arguments). In the function definition, you specify a comma-separated list of parameters inside parentheses:

def perform_calculation(a, b, c):
    result = a + b * c
    print(f'Calculation result: {result}')
perform_calculation(1, 2, 3)
3. Functions in Python - Positional arguments

In the example above, during a function call, the Python sets values to variables in the following way:

All arguments we specified in the function definition must be provided to the function when you’re calling it.

If you provide fewer arguments, you’ll get the following error message:

Traceback (most recent call last):
   File "functions/positional_arguments.py", line 7, in 
     perform_calculation(1, 2)
 TypeError: perform_calculation() missing 1 required positional argument: 'c'

If you provide more arguments, you’ll get a slightly different error message:

Traceback (most recent call last):
   File "functions/positional_arguments.py", line 7, in 
     perform_calculation(1, 2, 3, 4)
 TypeError: perform_calculation() takes 3 positional arguments but 4 were given

Keyword arguments

When you’re defining a function, you can specify arguments in the form <argument>=<value>.

The such syntax allows you to specify default values for the function arguments, for example:

def perform_calculation(a=1, b=1, c=1):
    result = a + b * c
    print(f'Calculation result: {result}')
perform_calculation(1, 2, 3)
perform_calculation(b=1, a=2, c=3)
perform_calculation(a=2, c=4)
perform_calculation()
4. Functions in Python - Keyword arguments

As you can see from the execution results:

  • Python assigns all values provided during the function call to the function arguments in order
  • Any values specified in the <argument>=<value> format will be assigned only to specific function arguments
  • If no value is provided for the function argument, Python will use the default value for the argument

An unexpected argument for the function, for example:

perform_calculation(a=1, b=2, c=3, d=2)

This will lead to the following error message:

Traceback (most recent call last):
   File "functions/keyword_arguments.py", line 13, in 
     perform_calculation(a=1, b=2, c=3, d=2)
 TypeError: perform_calculation() got an unexpected keyword argument 'd'

It is important to remember that positional arguments can not follow keyword arguments.

If you call the function in the following way:

perform_calculation(a=1, b=2, 3)

You’ll get the following error message:

File "functions/keyword_arguments.py", line 13
     perform_calculation(a=1, b=2, 3)
                                  ^
SyntaxError: positional argument follows keyword argument

Reference vs. value

There are two types of objects available in Python:

  • Mutable – list, dictionary, set, and user-defined classes
  • Immutable – int, float, decimal, bool, string, tuple, and range

Python passes all immutable objects to the function by value, which means that if you modify an immutable object within the function, its value will remain unchanged outside of the function:

a = 1
def my_function(my_argument):
    my_argument = 2
print(f'a = {a}')
6. Functions in Python - Immutable object argument

On another side, Python assigns mutable objects to variables by reference.

That means, if you modify a mutable object within the function, object changes will be accessible outside of the function:

a = []
def my_function(my_list):
    my_list.append('*')
my_function(a)
print(f'a = {a}')
7. Functions in Python - Mutable object argument

Mutable default arguments

We can use mutable objects as default values for the function arguments, for example:

def my_function(my_list=[]):
    my_list.append('*')
    print(f'my_list values: {my_list}')
my_function(['*'])
my_function(['*'])
5. Functions in Python - Mutable objects as default argument values

Nothing strange is happening. Our function is adding elements to the list as expected.

Now let’s take a look at what is going to happen if we will call the same function without arguments:

def my_function(my_list=[]):
    my_list.append('*')
    print(f'my_list values: {my_list}')
my_function()
my_function()
8. Functions in Python - Mutable objects as default argument values

In the example above, as soon as we did not provide any arguments to the function, Python created a mutable list during the first function call and continued using it for all other calls.

In summary, you should be extra careful when modifying mutable objects within your code.

Return statement

Any function in Python can have optional return statement that exits a function and optionally passes back an expression to the caller.

Here’s the return statement syntax:

return [expression]

Let’s modify one of our previous examples to illustrate how the return statement work:

def perform_calculation(a, b, c):
    result = a + b * c
    return result
b = perform_calculation(1, 2, 3)
print(f'Function returned: {b}')
9. Functions in Python - Return statement

Note: A return statement with no arguments is the same as return None.

Arbitrary arguments

Positional and keyword arguments allow us to pass a limited amount of arguments to the function.

But what if we need a function to process command-line arguments and cannot predict how many arguments the function will get?

To solve this specific problem, Python provides us with arbitrary arguments:

def function_name([arguments,] *args, **kwargs):
    """function_docstring"""
    code_statement(s)
    [return expression]

Here:

  • *args – arbitrary list of positional arguments (tuple)
  • **kwargs – arbitrary list of keyword arguments (dict)

Here’s how you’re processing those arguments:

def print_args(x, *args, **kwargs):
    """Function prints all passed arguments"""
    print(f'x = {x}')
    print('Printing arbitrary positional arguments:')
    for arg in args:
        print(f'arg = {arg}')
    print('Printing arbitrary keyword arguments:')
    for kw in kwargs:
        print(f'{kw} = {kwargs[kw]}')
print_args(1, 2, 3, y=4, name='Andrei')
10. Functions in Python - Arbitrary arguments

Assigning function to a variable

In Python, everything is an object, and function is not an exception.

That means you can assign a function to a variable and use this variable to call the function:

def my_sum(x, y):
    return x + y
my_sum_2 = my_sum
result = my_sum_2(1, 2)
print(f'Result: {result}')
12. Functions in Python - Assigning function to variable

Passing function as an argument

As soon as we can assign functions to variables, it becomes possible to pass a function as an argument to another function:

def my_sum(*args):
    result = 0
    for arg in args:
        result += arg
    return result
def my_mult(*args):
    result = 1
    for arg in args:
        result *= arg
    return result
def my_calc(func, *args):
    return func(args)
sum_result = my_calc(my_sum, 1, 2)
mult_result = my_calc(my_mult, 3, 4)
print(f'Sum: {sum_result}')
print(f'Mult: {mult_result}')
13. Functions in Python - Passing function as an argument

In the example above, the function my_calc applies the my_sum or my_mult function to calculate the sum or multiplication result of all provided arguments.

Anonymous or lambda functions

Now, we can extend the concept of assigning a function to a variable by introducing anonymous or lambda functions.

These functions are called anonymous because they are declared in a non-standard way (without using the def keyword).

Instead of using def keyword, we’re using lambda keyword to create them.

Here are some notes about lambda functions in Python:

  • It can take any number of arguments, but it returns only one value
  • It can not contain commands or multiple expressions
  • Lambda function is a short one-line function

The syntax of the lambda function in Python:

lambda [arg_1[, arg_2, ..., arg_n]]: expression

Now, let’s implement a simple lambda function that sums up two arguments:

my_sum = lambda x, y: x + y;
result = my_sum(1, 2)
print(f'Result: {result}')
11. Functions in Python - Lambda functions

Line 1 from the example above is equivalent to the following normal function definition:

def my_sum(x, y):
    return x + y

Python function annotations

Function annotation is a feature of Python for documenting a function.

Annotations provide a way to attach metadata to a function’s parameters and return value:

def my_sum(x: int, y: int) -> int:
    return x + y

The such syntax allows developers to get a better understanding of what type of parameters the function expects and what type of result it should return.

This annotation information is available at __annotations__ attribute of the function:

14. Functions in Python - Annotations

You may use more complex types to annotate your functions:

def my_sum(
    x: {
        'description': 'first argument',
        'type': int
    },
    y: {
        'description': 'second argument',
        'type': int
    }) -> \
    {
        'description': 'sum of x and y',
        'type': int
    }:
    return x + y
sum_result = my_sum(1, 2)
print(f'Sum: {sum_result}')
print(f'Annotations: {my_sum.__annotations__}')
15. Functions in Python - Annotations (dict)

Summary

This article covered almost everything you need to know about functions in Python, including function types, syntax, positional, keywords, arbitrary arguments, and return statements. In addition, we’ve provided many additional examples to cover assigning function to a variable, passing a function as an argument, anonymous or lambda functions, and function annotations.

Similar Posts