Better Programming

Advice for programmers.

Follow publication

Stop Abusing *args and **kwargs in Python

They’ll come back to haunt you…

Eden Au
Better Programming
Published in
3 min readFeb 4, 2020
Photo by Matthew Henry on Unsplash

There are many tutorials online that aim to teach you how to use *args and **kwargs when defining a function in Python. Perhaps you’ve already spent hours trying to figure out how you could unleash their potential. Maybe, after all that study, you now feel confident about them.

Don’t!

Powerful tools are dangerous. You may have made your day easier but mark my words, it will come back and haunt you later.

But why?

Some Basics

Parameters in a Python function can accept two types of arguments:

  • Positional arguments that are passed positionally.
  • Keyworded arguments that are supplied by keywords.
def foo(start, end):
print(start, end)

For example, foo('Hi', end='Bye!') feeds a positional argument, 'Hi', and a keyword argument 'Bye!' with keyword end to function foo. Parameters of a function are pre-defined; the number of parameters accepted in a function is fixed. However, that’s not always the case.

*args allows you to pass an arbitrary number of positional arguments to your function. The asterisk * is an unpacking parameter. They are packed as an iterable tuple inside the function.

On the other hand, **kwargs allows you to pass a varying number of keyworded arguments to your function. Since each keyworded argument has a keyword and a value, it’s grouped as an iterable dictionary inside the function.

Photo by Susan Holt Simpson on Unsplash

The Problem

You do not really need *args and **kwargs in most cases. How often do you not know how many arguments a pre-defined function should receive?

Code is much harder to debug if you abuse them because you’re letting an arbitrary number of arguments be passed to the function, and the function might have unpredictable behaviour.

Explicit is better than implicit. — The Zen of Python

When to Use It?

In short: Use them when you really need them. For instance, a function with a lot of optional fields and some of them are used only in some situations. Say, a function plots a graph and you can pass various optional arguments to modify its colour, style, size etc.

Every time you use *args and/or **kwargs, make sure you make very clear documentation to avoid confusion.

There is one scenario where their use might be inevitable. If you’re creating a wrapper for a function with unknown arguments, you would then have to accept an arbitrary number of positional and keyword arguments, then pass them to the function.

For example, decorators in Python work as wrappers that change the behaviour of the code, without changing the function code itself, thus augmenting extra functionalities.

Photo by Alexander Schimmeck on Unsplash

In the following example, we build trace that prints out the name of the executing function as a sanity check. The decorator is applied to a function using @trace on top of the function, as shown below. Since we want to apply this decorator to any functions with any number of arguments, we need to use *args and **kwargs.

Takeaways

Avoid them if possible.

Note that args and kwargs are just named by convention. You can name them whatever you like. It is the asterisks * and ** that make them powerful.

Thanks for reading! You can sign up for my newsletter to receive updates on my new articles. If you’re interested in improving your Python skills further, the following articles might be useful:

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (8)

Write a response