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.
Table of contents
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 functioncode_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')

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:

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)

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()

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}')

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}')

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(['*'])

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()

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}')

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')

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}')

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}')

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}')

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:

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__}')

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.