Python Functions: Advanced Concepts

Do you know how to force keyword arguments, create a function decorator, create anonymous functions, or unpack an array or dictionary into a function’s arguments? In this article, Python functions advanced concepts, we’ll cover some of the more advanced concepts surrounding functions. I’ve put these in a separate article because I don’t want to confuse beginners with these concepts.

You may want to read our introduction to Python functions first.

Forced keyword arguments

Keyword arguments have a number of advantages:

  • You’re not forced to a particular order in which you supply your arguments—the name matters, not the position.
  • Keyword arguments provide clarity. Without looking up the function itself, you can often guess what the argument is used for by looking at the names.

That’s nice, but you probably already knew these things. What you might not know is that you can also force keyword arguments. The details are described in PEP 3202, but it comes down to using an asterisk before the arguments you want to force as keyword arguments. Or, as shown below, before everything, forcing all arguments to be keyword arguments:

>>> def f(*, a, b):
...     print(a, b)
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional 
           arguments but 2 were given
>>> f(a=1, b=2)
1 2

This advanced function trick could come in handy when you’re developing some kind of library. Perhaps you don’t want to commit to a certain order of arguments (yet). In such cases, this is the way to force users of your library to use named arguments, making the order irrelevant.

Using * and ** for function arguments

Some functions require a long list of arguments. Although this should be avoided altogether, for example, by using data classes, it’s not always up to you. In such cases, the second-best option is to create a dictionary with all the named arguments and pass that to the function instead. It will generally make your code more readable. You can unpack a dictionary for use with named keywords by using the ** prefix:

>>> def f(a, b):
...     print(a, b)
>>> args = { "a": 1, "b": 2 }
>>> f(**args)
1 2

Similarly, we can use a single * to unpack a list and feed its content as positional arguments to a function:

>>> def f(a, b, c):
...    print(a, b, c)
>>> l = [1, 2, 3]
>>> f(*l)
1 2 3

Decorating your functions

Decorators are wrappers around a function that modify the behavior of the function in a certain way. There are many use-cases for decorators, and you may have used them before when working with frameworks like Flask. 

Let’s create our own decorator; it’s simpler than you might expect and might come in handy someday:

def print_argument(func):
    def wrapper(the_number):
        print("Argument for", func.__name__, "is", the_number)
        return func(the_number)

    return wrapper

def add_one(x):
    return x + 1


Inside print_argument, we define a wrapper function. This function prints the argument and the name of the called function. Next, it executes the actual function and returns its result as if the function was called regularly. With @print_argument we apply our decorator to a function. Perhaps unnecessary to say: this decorator can be re-used for other functions too.

The output of our little script will be:

Argument for add_one is 1

Anonymous functions

Sometimes, naming a function is not worth the trouble. An example is when you’re sure the function will only be used once. For such cases, Python offers us anonymous functions, also called lambda functions.

A lambda function can be assigned to a variable, creating a concise way of defining a function:

>>> add_one = lambda x: x + 1
>>> add_one(3)

It gets more interesting when you need to use a function as an argument. In such cases, the function is often used only once. As you may know, map applies a function to all elements of an iterable object. We can use a lambda when calling map:

>>> numbers = [1, 2, 3, 4]
>>> times_two = map(lambda x: x * 2, numbers)
>>> list(times_two)
[2, 4, 6, 8]

In fact, this is a pattern that you’ll see often. When you need to apply a relatively simple operation on each element of an iterable object, using map() in combination with a lambda function is concise and efficient.

Please share this article with others!

Python Courses

Are you enjoying this free tutorial? Please also have a look at my premium courses. They offer a superior user experience with small, easy-to-digest lessons and topics, progress tracking, quizzes to test your knowledge, and practice sessions. Each course will earn you a downloadable course certificate.

The Python Fundamentals Course For Beginners
Now for $29 (from $59)

Python Fundamentals I is a course for beginners that will get you started with Python in no time. Learn all the essentials, test your progress with quizzes and assignments, and bring it all together with the final course project!

Python Course for Beginners

Modules, Packages, And Virtual Environments
Now for $29 (from $59)

Python Fundamentals II covers creating your own modules and packages, using virtual environments and Python package managers to make your life as a programmer easier. Advance your productivity as a Python programmer!

Python Fundamentals 2

Leave a Comment

Share to...