Define and call functions in Python (def, return)

Modified: | Tags: Python

This article provides a comprehensive guide to defining and calling (executing) functions in Python.

Refer to the following articles for information on lambda expressions, docstrings, and command line arguments.

You can find the official documentation for defining functions here:

How to define and call a function in Python

In Python, functions are defined using def statements, with parameters enclosed in parentheses (), and return values are indicated by the return statement.

def function_name(parameter1, parameter2...):
    do_something
    return return_value

Note that blocks are expressed with indentation (usually four spaces) rather than brackets.

To call a defined function, use the following syntax:

function_name(argument1, argument2...)

Example:

def add(a, b):
    x = a + b
    return x

x = add(3, 4)
print(x)
# 7

Parameters and return values can be omitted if not necessary.

def hello():
    print('Hello')

hello()
# Hello

Detailed explanations about arguments and return values are provided below.

Note that while the Python coding standard PEP8 recommends leaving two blank lines before and after top-level function definitions, only one blank line is used in the sample code for convenience.

Positional and keyword arguments

Parameters are defined by separating them with commas inside the parentheses of function_name(). The following example demonstrates a simple function that outputs the arguments using f-strings.

def func(a, b, c):
    print(f'a={a}, b={b}, c={c}')

Positional argument

When calling a function, specify the values in the defined order.

func(1, 10, 100)
# a=1, b=10, c=100

If the number of values specified when calling the function does not match the number of parameters in the function definition, a TypeError will occur.

# func(1)
# TypeError: func() missing 2 required positional arguments: 'b' and 'c'

# func(1, 10, 100, 1000)
# TypeError: func() takes 3 positional arguments but 4 were given

Keyword argument

You can specify a value as parameter_name=value when calling a function. In this case, the arguments can be specified in any order.

func(b=10, c=100, a=1)
# a=1, b=10, c=100

Not all arguments need to be specified by keywords. You can specify some arguments by position and others by keyword. However, after specifying an argument by keyword, all subsequent arguments must also be specified by keywords.

func(1, c=100, b=10)
# a=1, b=10, c=100

# func(a=1, 10, 100)
# SyntaxError: positional argument follows keyword argument

Positional/keyword-only parameter

Positional-only parameter (Python 3.8 or later)

When defining a function, if / is used as a parameter, the parameters preceding / are treated as positional-only.

Positional-only parameters cannot be passed by keyword. Parameters after / can be passed by keyword.

def func_pos_only(a, b, /, c):
    print(f'a={a}, b={b}, c={c}')

# func_pos_only(a=1, b=10, c=100)
# TypeError: func_pos_only() got some positional-only arguments passed as keyword arguments: 'a, b'

func_pos_only(1, 10, 100)
# a=1, b=10, c=100

func_pos_only(1, 10, c=100)
# a=1, b=10, c=100

If you define a function with / at the end, such as func(a, b, c, /), all parameters are positional-only.

The positional-only parameter using / was introduced in Python 3.8 and unavailable in earlier versions.

Keyword-only parameter

When defining a function, if * is used as a parameter, the parameters following * are treated as keyword-only.

Keyword-only parameters must be specified by keywords, while parameters before * can be specified by either position or keyword.

def func_kw_only(a, b, *, c):
    print(f'a={a}, b={b}, c={c}')

# func_kw_only(1, 10, 100)
# TypeError: func_kw_only() takes 2 positional arguments but 3 were given

func_kw_only(1, 10, c=100)
# a=1, b=10, c=100

func_kw_only(1, c=100, b=10)
# a=1, b=10, c=100

If you define a function with * at the beginning, such as func(*, a, b, c), all parameters are keyword-only.

Positional-only parameter and keyword-only parameter

You can use / and * simultaneously in a function definition. Parameters before / are position-only, those after * are keyword-only, and those between / and * can be specified by either position or keyword.

def func_pos_kw_only(a, /, b, *, c):
    print(f'a={a}, b={b}, c={c}')

# func_pos_kw_only(1, 10, 100)
# TypeError: func_pos_kw_only() takes 2 positional arguments but 3 were given

# func_pos_kw_only(a=1, b=10, c=100)
# TypeError: func_pos_kw_only() got some positional-only arguments passed as keyword arguments: 'a'

func_pos_kw_only(1, 10, c=100)
# a=1, b=10, c=100

func_pos_kw_only(1, c=100, b=10)
# a=1, b=10, c=100

You cannot use / before *.

# def func_pos_kw_only(a, *, b, /, c):
#     print(f'a={a}, b={b}, c={c}')
# SyntaxError: invalid syntax

Default parameter values

You can set a default value for a parameter by defining parameter_name=default_value in the function definition.

If a default value is set, you can omit the argument when calling the function. Of course, if you specify a different value, that value will be used.

def func_default(a, b, c=100):
    print(f'a={a}, b={b}, c={c}')

func_default(1, 10)
# a=1, b=10, c=100

func_default(1, 10, 200)
# a=1, b=10, c=200

Placing a default parameter before an ordinary parameter without a default value in the function definition causes a SyntaxError.

# def func_default(a=1, b, c=100):
#     print(f'a={a}, b={b}, c={c}')
# SyntaxError: non-default argument follows default argument

Note that using mutable objects, such as lists or dictionaries, as default values can lead to unexpected behavior, as the same objects will always be used when calling the function. For more details, see the following article.

Variable-length arguments

When defining a function, you can add * and ** to parameter names to allow variable-length arguments. This enables you to specify any number of arguments when calling the function.

By convention, *args and **kwargs are often used, but other names with * and ** prefixes are also acceptable.

*args: Receive multiple arguments as a tuple

If you prefix a parameter name with *, multiple arguments will be received as a tuple.

def func_args(*args):
    print(args)

func_args(1, 10)
# (1, 10)

func_args(1, 10, 100, 1000)
# (1, 10, 100, 1000)

**kwargs: Receive multiple keyword arguments as a dictionary

If you prefix a parameter name with **, multiple keyword arguments will be received as a dictionary (dict).

def func_kwargs(**kwargs):
    print(kwargs)

func_kwargs(a=1, b=10)
# {'a': 1, 'b': 10}

func_kwargs(c=1, b=10, d=1000, a=100)
# {'c': 1, 'b': 10, 'd': 1000, 'a': 100}

Be careful about the order when combining positional arguments with *args and **kwargs. See the following article for details.

Unpack lists, tuples, and dictionaries

Unpack lists or tuples

When calling a function, prefixing a list or tuple with * unpacks its elements and specifies them as positional arguments. A TypeError is raised if the number of elements in the list or tuple does not match the number of arguments in the function.

def func(a, b, c):
    print(f'a={a}, b={b}, c={c}')

l = [1, 10, 100]
func(*l)
# a=1, b=10, c=100

l = [1, 10]
# func(*l)
# TypeError: func() missing 1 required positional argument: 'c'

Unpack dictionaries

If you prefix a dictionary with ** when calling a function, its keys and values are unpacked as names and values of the arguments and specified as keyword arguments. A TypeError is raised if the number of keys in the dictionary does not match the number of argument names in the function, or if there are non-matching keys.

d = {'a': 1, 'b': 10, 'c': 100}
func(**d)
# a=1, b=10, c=100

d = {'a': 1, 'b': 10, 'x': 100}
# func(**d)
# TypeError: func() got an unexpected keyword argument 'x'

For more information, see the following article.

Return value

Basics of return

The return value of the function is specified by the return statement.

def func_return(a, b):
    return a + b

x = func_return(3, 4)
print(x)
# 7

print(type(x))
# <class 'int'>

The return value type depends on the types of the arguments and the processing within the function.

x = func_return(0.3, 0.4)
print(x)
# 0.7

print(type(x))
# <class 'float'>

Functions that return None

return is not mandatory in a function and can be omitted if it is unnecessary to return a value.

A function without return returns None. In the following example, pass is used to prevent an error when the def block is empty.

def func_none():
    # do something
    pass

x = func_none()
print(x)
# None

If you omit the value after return, None is returned.

def func_none2():
    return

x = func_none2()
print(x)
# None

Of course, you can explicitly write return None.

def func_none3():
    return None

x = func_none3()
print(x)
# None

Specify multiple return values

Specifying multiple values separated by commas with return returns a tuple.

def func_return_multi(a, b):
    return a + b, a * b, a / b

x = func_return_multi(3, 4)
print(x)
# (7, 12, 0.75)

print(type(x))
# <class 'tuple'>

You can unpack each value and assign it to a variable.

x, y, z = func_return_multi(3, 4)
print(x)
# 7

print(y)
# 12

print(z)
# 0.75

Related Categories

Related Articles