One of the cool features of Python is the concept of positional and keyword arguments. In this article, we will explore these two types of arguments and then discuss the right place to use each one.

Positional arguments

Imagine we have a function `sub` like this

``````def sub(a, b):
return a - b``````

We can call this function as follows

``total = sub(10, 5)``

In this example, the first parameter `a` is bound to the first value `10` and the second parameter `b` is bound to the second value `5`. Therefore, the returned result will be `10 - 5 = 5`

Here, the parameters are bound to the values based on their position. Therefore these kinds of arguments are called positional arguments.

Keyword arguments

While positional arguments are very common, Python supports another way of passing arguments called keyword arguments. Take a look at the function call below

``total = sub(b=10, a=5)``

In this example, we explicitly specify which parameter should be bound to which value. So `b` will bind to the value `10` and `a` will bind to `5` and the answer will be `-5`. This form of argument is called keyword argument. When we use keyword arguments, the position is not relevant since the keyword tells which parameter the value should be bound to.

We can also mix both forms as in this example below

``````def calc(a, b, c):
return a - b + c

value = calc(10, c=3, b=2) # 11``````

Here, the value `10` is a positional argument and it gets mapped to `a`. The remaining parameters `c=3` and `b=2` are keyword parameters and mapped to `c` and `b` respectively.

Note that when mixing forms, all the positional arguments have to come first, followed by the keyword arguments.

When to use each form?

While positional and keyword arguments are easy to understand, what is not so easy is to know when to use each one. Should you call a function with positional arguments? Keyword arguments? A mix?

Here is a simple rule-of-thumb to determine this:

• Core parameters are generally positional. What are core parameters? These are the parameters that are required for the function to run
• Options, flags and configurations are generally keyword. These parameters are not the core parameters for the function, but modify how the function behaves

That sounds a little abstract, so let us look at a concrete example. Below is the function signature for the `copyfile` function from the `shutil` module in the standard library.

``shutil.copyfile(src, dst, follow_symlinks=True)``

As the name implies, this function copies a file from one place to another. So the `src` and `dst` parameters are core for the function.

Additionally, there is a flag `follow_symlinks`. This flag is not a core part of the function operation, but it changes up how the function behaves. Therefore this parameter should be a keyword parameter.

Enforcing positional or keyword arguments

In the example above, although we know which parameters should be positional and which should be keyword, there is nothing stopping the caller from mixing the parameters. For example, a user might call the function like this

``copyfile('file1.txt', 'file2.txt', True)``

Here we are passing the `follow_symlink` parameter as a positional argument. This obscures the meaning of the function call. How can we enforce it to be a keyword-only argument?

Python gives us a way to do this.

Here is the full function signature for shutil.copyfile

``shutil.copyfile(src, dst, *, follow_symlinks=True)``

Notice that `*` in the signature. This signifies that all parameters after that symbol should be keyword only. Here is what happens if we try to call this function with only positional arguments

``````>>> shutil.copyfile('file1.txt', 'file2.txt', True)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: copyfile() takes 2 positional arguments but 3 were given``````

The error it says that there should only be two positional arguments (`src` and `dst`) while we passed three. The `follow_symlink` parameter can only be a keyword argument.

On the other hand, this function call will work

``shutil.copyfile('file1.txt', 'file2.txt', follow_symlinks=True)``

In a similar vein, we can also enforce some arguments to be positional only. Here is the function signature for the commonly used len function.

``len(obj, /)``

Here the `/` symbol denotes that all the parameters to the left of it should be positional only. Therefore, this call gives an error

``````>>> len(obj=[1, 2, 3])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: len() takes no keyword arguments``````

And both of these symbols can be combined. Here is the function signature of the exec built-in function

``exec(object, globals=None, locals=None, /, *, closure=None)``

For this function, the parameters `object`, `globals` and `locals` have to be passed as positional only because they appear to the left of the `/`. On the other hand, `closure` is a keyword only argument because it appears to the right of the `*`. If there were any arguments between the two symbols, those arguments could be passed using either style.

An interesting thing to note with the `exec` function signature is that `globals` and `locals` have default values. Therefore, it is not mandatory to pass those options. But if you do pass in values for those parameters, then it has to be positional. Clearly the python core developers think that these two parameters are a core part of the `exec` function.

Other considerations

While deciding whether a parameter is core or an option is the main consideration, there are others:

• Keyword arguments are explicit and when reading the function call, we can easily understand which parameters are bound to which values without having to go and look up the function signature
• On the other hand, with positional arguments, if we do not know the function signature, we will have to look it up before we can understand the function call
• Conversely, if we rename any parameter in the function signature, it will break all code that uses that parameter as a keyword parameter. On the other hand, positional arguments are unaffected by renaming parameters in the function signature

Summary

In this article, we took a look at positional and keyword arguments. While the concept is easy to understand, there are subtle nuances when deciding which to use in your code. Apart from supporting both types of arguments, Python also allows us to enforce parameters to be positional-only or keyword-only. Hopefully this article has given a deeper understanding into how to use these two types of arguments.