mutable defaults for function parameters considered evil
Submitted by
reedstrm.
on 2009-12-16 11:48.
Providing a mutable type (like a list) as the default for a python function parameter can have unforeseen consequences.
Consider the lowly function def:
>>> def addit(it, stuff=[]):
... stuff.append(it)
... return stuff
...
>>> addit('this')
['this']
>>> addit('that')
['this', 'that']
>>> addit('theother')
['this', 'that', 'theother']
>>> addit('thing2',['thing1'])
['thing1','thing2']
>>> addit('onemore')
['this', 'that', 'theother', 'onemore']
>>>
What's going on here?
Default params for functions are evaluated at function definition time, so our default for stuff is a single list, stored in addit.func_defaults. Each call to addit that uses the default uses the same list.
The way around this is to initialize stuff to None, and provide a fresh empty list:
>>> def addit(it, stuff=None):
... stuff = stuff or []
... stuff.append(it)
... return stuff
...
>>> addit('this')
['this']
>>> addit('that')
['that']
>>> addit('theother')
['theother']
>>> addit('thing',['thing2'])
['thing2', 'thing']
>>> addit('thing2',['thing1'])
['thing1', 'thing2']
>>> addit('onemore')
['onemore']
One last caveat: unless the caller is explicitly expecting the function to modify the passed in list, it's probably best to make a copy:
>>> def addit(it, stuff=None): ... stuff = stuff and stuff[:] or [] ... stuff.append(it) ... return stuff ...
