Python's excess arguments

programming python

What I've always really appreciated of python is the ability to give a function an arbitrary number of positional and keyword arguments, something that in PHP is not possible and is indeed very powerful.

When declaring a function, we can define 4 different types of arguments:

  • required arguments
  • optional arguments (a default is provided)
  • excess positional arguments
  • excess keyword arguments

for example:

def myfunc(a, b=3, *c, **d)
  • a is a required argument
  • b is an optional one since it's default value it's 3
  • the single asterisk before the c argument allows the function to accept any number of positional arguments
  • the two asterisks before the d argument allow the function to support arbitrary kewyword arguments

The order of such arguments is important!

As you've seen you're free to give the excess positional and keyword arguments the name you prefer, but as a python convention they are often called *args and **kwargs.

Now let's see some examples to clarify these concepts.

>>> def sum(*args):
...   s = 0
...   for arg in args:
...     s += arg
...     return s
>>> sum(2, 3, 5)
>>> sum(1,2,3,4,5,6)

So we are able to write a simple function which can sum an arbitrary number of numbers, in PHP we should have used arrays instead.

We can use the **kwargs argument to accept an arbitrary number of named options:

>>> def render(context, **kwargs):
...   template = kwargs['template'] if 'template' in kwargs else 'my_default_template'
...   # do something with your template
...   print template
>>> render()
>>> render(template='custom_template')

The excess keyword arguments were used for example in django to customize the generic views and make them adaptable to many different situations (https://docs.djangoproject.com/en/1.4/topics/generic-views/).

On the other hand, python code may call functions with any number of arguments using the same asterisk notation. Arguments passed in this way are expanded into a normal list of arguments. Take care when passing keyword arguments together with tuple as excess positional arguments, since python will apply the previously described ordering rules, so the positional arguments would come first! Some examples:

>>> def concatenate(a, b, c): 
... return '%s%s%s' % (a, b, c) 
>>> concatenate(1, 2, 3)
>>> concatenate(5, b='K', c='g')
>>> concatenate(5, *('K', 'g'))
>>> concatenate(a=5, *('K', 'g'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: concatenate() got multiple values for keyword argument 'a'

As you can see in the last example, we got an error since the positional arguments passed as a tuple are considered first by the python interpreter causing a re-assignment of the argument a

All this is quite simple, but I have to admit then when approaching to python and django the first times (and coming from a PHP background) such *args and **kwargs were something mysterious to me.

Subscribe to abidibo.net!

If you want to stay up to date with new contents published on this blog, then just enter your email address, and you will receive blog updates! You can set you preferences and decide to receive emails only when articles are posted regarding a precise topic.

I promise, you'll never receive spam or advertising of any kind from this subscription, just content updates.

Subscribe to this blog

Comments are welcome!

blog comments powered by Disqus

Your Smartwatch Loves Tasker!

Your Smartwatch Loves Tasker!

Now available for purchase!