Default Argument Inconsistency?

Peter Otten __peter__ at web.de
Tue Apr 27 11:53:14 CEST 2004

```Paul Sweeney wrote:

> The python tutorial gives the following example to demonstrate the fact
> that default args are only evaluated once:
>
> def f(a,L=[]):
>     L.append(a)
>     return L
>
> print f(1),f(2),f(3)
> [1] [1,2] [1,2,3]
>
> now I'm confident I understand this, but I do not understand how changing
> to the following (whatever the merits of so doing, it was an accidental
> typo)
> results in the output displayed:
>
> def f(a,L=[]):
>     if not L: L=[]

The first thing in f() is to check if L evaluates to False, i. e. is empty.
If L is empty the L "the object" is left alone, but L "the identifier" is
bound to a new empty list. So

>     L.append(a)

will never operate on the empty list that was provided as default parameter.

>     return L
>
>>>> print f(1),f(2),f(3)
> [1] [2] [3]
>
> surely on second entry to f, L == [1], so the "if not L:" should not
> fire?!

While the above works, there is one pitfall that will sooner or later bite
you:

>>> def f(a, L=[]):
...     if not L: L = []
...     L.append(a)
...     return L
...
>>> l1 = ["old"]
>>> f("new", l1)
['old', 'new']
>>> l1
['old', 'new']
>>> l2 = []
>>> f("new", l2)
['new']
>>> l2
[]
>>>

Did you predict the values of l1 and l2 correctly? Congratulations.

I recommend that you adopt the common practice and initialize mutable
parameters with None as the default, which gives you consistent behaviour:

>>> def f(a, L=None):
...     if L is None: L = []
...     L.append(a)
...     return L
...
>>> l1 = ["old"]
>>> f("new", l1)
['old', 'new']
>>> l1
['old', 'new']
>>> l2 = []
>>> f("new", l2)
['new']
>>> l2
['new']
>>>

Peter

```