Watch out with default parameters for keyword arguments

Tags: python, book

Keyword arguments (“kwargs”) are handy. A former colleague (thanks!) once warned me about a kwargs gotcha that I didn’t know about. I thought “let’s add the warning to my Django book”, but it is a bit too specialistic and it detracts too much from the main flow of the text. So I’m taking it out and posting it here. (It is also quite hard to explain; I’m still not quite happy with this text. But I’m not going to do more tweaking.)

Watch out with the type of default parameters for keyword arguments! Technically: immutable types are fine, mutable types not. In plain language it means that name='thatcher', amount=5 and template=None are all fine.

But don’t use lists or dictionaries. In Python, a variable name is just a pointer to a memory address. If you do something like amount = amount + 4, amount would start pointing at a new memory adress. Just open a Python prompt and type in the following piece of code to test it out:

>>> def example(immutable=5, mutable={'amount': 0}):
...     print immutable
...     print mutable
...     mutable['amount'] += 10
>>> example()
{'amount': 0}
>>> example()
{'amount': 10}
>>> example()
{'amount': 20}

We probably wanted to pass in a dictionary with some defaults already in place. However, this backfires because we’re changing values inside the very same dictionary that our keyword points to by default.

The problem is that every variable in Python is only a memory pointer to a value. With an immutable value, a new value means a fresh pointer. The contents of a mutable value, like a list, can be changed in-place without the pointer to the actual list changing; that is the whole point of them.

The solution is straightforward once you’ve seen it. For dictionaries and lists where you want a default, pick None as the default value and check for that like this:

def example(immutable=5, mutable=None):
    if mutable is None:
        mutable = {'amount': 0}
    mutable['amount'] += 10

So there you have it!

blog comments powered by Disqus logo

About me

My name is Reinout van Rees and I work a lot with Python (programming language) and Django (website framework). I live in The Netherlands and I'm happily married to Annie van Rees-Kooiman.

Weblog feeds

Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):