Strange behavior of default function parameters in Python

Sometimes things don’t work in the way we want them to. Today I was asked why this piece of code is not working properly (OK, given problem was a bit different and much more “real-life-applicable”, but it’s just an example):

1
2
3
4
5
6
7
8
9
def mypush(val, mylist=[]):
	mylist.append(val)
	print mylist, ': ', id(mylist)
 
lst = []
mypush(1, lst)
mypush(2, lst)
mypush(1)
mypush(2)

The output is:

1
2
3
4
[1]    :  139750946213184
[1, 2] :  139750946213184
[1]    :  139750946218496
[1, 2] :  139750946218496

What’s wrong with it? NOTHING – that’s the way Python should and will behave in such case.

Do you agree? If yes – stop reading, because you won’t learn anything new. Go to XKCD instead. If no – here’s a brief explaination:

You may think that first two pushes are fine (they add elements to the same list, defined in line 5), but next two are not, because they add elements to the list which is a function parameter’s default, which should be created each time the function is invoked. But, even if it sounds senssible, it’s not the way Python handles defaults. You may argue that Python Reference says: “Default parameter values are evaluated when the function definition is executed”. OK, fair enough. But it also says: “(…) the expression is evaluated once, when the function is defined, and that the same ‘pre-computed’ value is used for each call”.

Again: default parameters are evaluated ONCE – when the function is DEFINED*.

Keep that in mind.

How to deal with it? Simply do NOT use mutable objects as default parameters. Replace them with None and assign an empty list “manually” each time None is provided. Like this:

1
2
3
4
5
6
7
8
9
10
11
def mypush(val, mylist=None):
        if mylist is None:
                mylist = []
        mylist.append(val)
        print mylist, ': ', id(mylist)
 
lst = []
mypush(1, lst)
mypush(2, lst)
mypush(1)
mypush(2)

The output is:

1
2
3
4
[1]    :  139775841198592
[1, 2] :  139775841198592
[1]    :  139775841332184
[2]    :  139775841332184

Comments are closed.