Skip to content
Home » The Order of Arguments

The Order of Arguments

Spread the love

Today we’ll be talking about the order of arguments.

order of arguments

If you haven’t read my article on argument matching modes in Python, you may want to read it first.

As mentioned in the previous articles, there are several types of arguments:

– positional arguments

– keyword arguments

– default arguments

– * arguments

– ** arguments

I briefly mentioned what order they must be in if more than one type is passed to a function. But in this article, we’ll talk about it in more detail.

Order of Positional and Keyword Arguments

So, if there are both positional and keyword arguments, the positional ones must come first in the function call. Have a look:

>>> def func(a, b, c, d):
...     return a + b + c + d
... 
>>> func(4, 5, d = 1, c = 6)
16

Otherwise it won’t work:

>>> func(c = 6, d = 1, 4, 5)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

By the way, keyword arguments may be in any order.

Your Panda3D Magazine

Make Awesome Games and Other 3D Apps

with Panda3D and Blender using Python.

Cool stuff, easy to follow articles.

Get the magazine here (PDF).

Order of Default and Mandatory Arguments

Now, if there are default arguments, they must follow mandatory arguments. Have a look:

>>> def func(a, b, c = 3, d = 5):
...     return a + b + c + d
... 

If we don’t pass the default arguments, their default values will be used:

>>> func(1, 2)
11

If we do pass the default arguments, their default values will be overwritten:

>>> func(1, 2, 4, 8)
15

We can use keyword arguments to reassign just some of the default arguments, skipping the others. Have a look:

>>> def func(a, b, c = 5, d = 3, e = 7, f = 4):
...     return a + b + c + d + e + f
... 

Now if we want to pass a different value just for e, we can use the keyword argument like so:

>>> func(1, 2, e = 10)
25

Or if we want to deliver different values for d and f only:

>>> func(1, 2, d = 1, f = 5)
21

Without keyword arguments, if we wanted to pass a different value for f, we would still have to repeat all the default values of the preceding default arguments because these are positional arguments.

>>> func(1, 2, 5, 3, 7, 10)
28

If we wanted to pass a different value for d, we would still have to repeat the default value of c, because it precedes d:

>>> func(1, 2, 5, 8)
27

* and ** Arguments

And now the harder part: the * and ** arguments. What is the order of arguments if we have such arguments in the function?

Python Jumpstart Course

Learn the basics of Python, including OOP.

with lots of exercises, easy to follow

The course is available on Udemy.

* and ** Arguments in Function Definitions

In function definitions we use a single star to pack all the unmatched positional arguments in a tuple. The double star is used to pack all the unmatched keyword arguments in a dictionary.

Here are two simple examples that demonstrate how they work:

– with positional arguments:

>>> def func(*args):
...     print(args)
... 
>>> func(1, 2, 3, 4, 5, 6)
(1, 2, 3, 4, 5, 6)

– with keyword arguments:

>>> def func(**kwargs):
...     print(kwargs)
... 
>>> func(a = 1, b = 2, c = 3, d = 4)
{'a': 1, 'b': 2, 'c': 3, 'd': 4}

If we need both positional and keyword arguments in a function, then first come all single positional arguments, then we can use the * notation to pack all the remaining positional arguments in a tuple, and last come the keyword arguments packed in a dictionary using the ** notation:

>>> def func(a, *b, **c):
...     print(a, b, c)
... 
>>> func(4, 5, 6, 7, m = 10, n = 20, p = 50, s = 90)
4 (5, 6, 7) {'m': 10, 'n': 20, 'p': 50, 's': 90}

Blender Jumpstart Course

Learn the basics of 3D modeling in Blender.

step-by-step, easy to follow, visually rich

The course is available on Udemy and on Skillshare.

* and ** Arguments in Function Calls

When we use the * and ** notation in function calls, we unpack tuples (or other iterables) and dictionaries into individual positional and keyword arguments respectively. The order is the same as in function definitions, so * precedes **.

Here are some examples:

>>> def func(a, b, c, d, e, f):
...     return a + b + c + d + e + f 
... 
>>> func(1, 2, 3, 4, 5, 6)
21

>>> func(1, 2, *(3, 4, 5, 6))
21

>>> func(*(1, 2), **{'c': 3, 'd': 4, 'e': 5, 'f': 6})
21

>>> func(1, *(2, 3, 4), **{'e': 5, 'f': 6})
21

Keyword-Only Arguments

Things get even more interesting if we add keyword-only arguments to the lot.

If you don’t know what keyword-only arguments are, I have an article about them too, so feel free to read it first.  

We know that keyword–only arguments must follow * arguments in the function definition. But if we also have ** arguments in the definition, then the keyword-only arguments must precede them. This means the keyword-only arguments must come between the * arguments and the ** arguments. Have a look:

>>> def func(a, *b, c, **d):
...     print(a, b, c, d) 
... 

Here c is a keyword-only argument. Here’s how we can use the function:

>>> func(4, 5, 6, 7, c = 10, m = 20, n = 30, o = 40, p = 40)
4 (5, 6, 7) 10 {'m': 20, 'n': 30, 'o': 40, 'p': 40}

So, a is assigned 4, *b is assigned the tuple containing 5, 6 and 7. The keyword-only arguments c is passed with the value of 10 and then we have a dictionary with all the remaining keyword arguments assigned to d.

We can skip the keyword-only argument in the function call if we assign a default value to it in the function definition:

>>> def func(a, *b, c = 100, **d):
...     print(a, b, c, d) 
... 
>>> func(4, 5, 6, 7, m = 20, n = 30, o = 40, p = 40)
4 (5, 6, 7) 100 {'m': 20, 'n': 30, 'o': 40, 'p': 40}

In function calls we can use keyword-only arguments before or after * arguments. They can also follow the ** arguments:

>>> def func(a, *b, c, **d):
...     print(a, b, c, d)
...

– between * and **

>>> func(1, *(2, 3, 4), c = 5, **{'d': 6})
1 (2, 3, 4) 5 {'d': 6}

– after **

>>> func(1, *(2, 3, 4), **{'d': 6}, c = 5)
1 (2, 3, 4) 5 {'d': 6}

– before *

>>> func(1, c = 5, *(2, 3, 4), **{'d': 6})
1 (2, 3, 4) 5 {'d': 6}

It can also be included in the ** argument:

>>> func(1, *(2, 3, 4), **{'d': 6, 'c': 5})
1 (2, 3, 4) 5 {'d': 6}

Don’t worry if these rules look overwhelming. In most scenarios you don’t need all the different types of arguments in one function.

If you want to practice a bit, there will be a drill on function arguments in my next article, so stay tuned.

Here’s the video version of this article:


Spread the love

Leave a Reply