Python Pitfall: Mutable Default Arguments 2018-09-04

I’ve been programming in Python lately, and I found an interesting problem with one small program I wrote. If I had less experience in programming languages I might have been stuck on this for a long time. The issue is well known in the Python community, but to a relative beginner like me it is easy to get caught off guard by it. The problem has to do with default function arguments being mutable and reused between function calls. It’s easiest to explain this with an example.

This is a very condensed version of my problematic program:

def add(M, key, value=[]):
    if key in M:
        M[key] += value
        M[key] = value

add(M, 1)
add(M, 2)
add(M, 3, ['X'])
add(M, 2, ['Y'])
print M

My goal was to build a map M of keys to lists of values. Sometimes I wanted to just insert a key without a value, so the function for adding key/value pairs has an empty list as default value. If the key already exists, I add all elements of the value to that key.

Running the code above, I expected it to print

{1: [], 2: ['Y'], 3: ['X']}

but instead I got this

{1: ['Y'], 2: ['Y'], 3: ['X']}

The reason the value lists for key 1 and 2 are the same is that they are in fact the same object. When calling the function without specifying an argument for the value parameter, the same default list value is reused. The problem is that this object is mutable and next time I call the function to update the value for key 2, it modifies the value of the default parameter which is already used by both key 1 and 2.

Here is another program demonstrating the same problem:

def cons(head, tail=[]):
    tail.insert(0, head)
    return tail

print cons(1, cons(2, cons(3)))
print cons('hmm')

Running this gives the output

[1, 2, 3]
['hmm', 1, 2, 3]

This is a well-known feature of Python, and there are lots of blog posts on the net warning about it about it, for example this one.

Categories: Uncategorized

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.