2

This is covered by the Python Tutorial, but I still don't quite understand the reason why Python has this style. Is it purely convention, or is there some explanation behind why Python has the following style regarding default parameters:

My understanding is that Python prefers something=None as opposed to something=[] for default parameters for functions. But...why not use something=[]? Surely this is the convention in other languages, like C

As an example, take these two examples, which are equivalent

def function(arr, L=[]):
    L.append(arr)
    return L

and

def function(arr, L=None):
    if L is None:
        L = []
    L.append(arr)
    return L

My understanding is that the first is "incorrect style" for Python. Why?

EDIT: Ah, I finally understand. I am incorrect above: the two functions are NOT equivalent. Default arguments are evaluated once when the function is defined, not each time the function is called!

JesseTrevve
  • 293
  • 1
  • 3
  • 13
  • 4
    See http://docs.python-guide.org/en/latest/writing/gotchas/ – ferhatelmas May 14 '15 at 21:58
  • 2
    They *could* have had a block of code (like a lambda) run every time the function is called and create a *new* empty list. However this would 1. reduce performance unnecessarily, and 2. Make memoization/cache style code harder to write. Honestly it's a blessing that Python handles default arguments the way it does. – Shashank May 14 '15 at 22:02
  • 2
    Answered here http://stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument – Paul Rooney May 14 '15 at 22:08
  • Re your EDIT; Yes perfect :) Glad we could help! – James Mills May 14 '15 at 22:38

4 Answers4

5

When you set a parameter to the value of a list, it is assigned when the function is defined, not when it is called. That is why you'll get different results for calling the function multiple times with the same input parameter. Beware!!!

def function(arr, L=[]):
    L.append(arr)
    return L

arr = [1, 2, 3]

>>> function(arr)
[[1, 2, 3]]

>>> function(arr)
[[1, 2, 3], [1, 2, 3]]
Alexander
  • 105,104
  • 32
  • 201
  • 196
3

A default value that's an empty list will refer to one specific variable each time you call it, instead of creating a new empty list every time.

>>> def add(defList=[]):
        defList.append(1)
        return defList
>>> add()
[1]
>>> add()
[1,1]

It's a quirk of how mutable data works in Python. It could be occasionally useful, but often it's safer to use None. Then create an empty list if a value hasn't been passed.

SuperBiasedMan
  • 9,814
  • 10
  • 45
  • 73
3

The reason is that Python stores a value for L. In other words L is a reference to a constant. But that constant can be updated.

You can say that Python stores it as:

               |-->  []
               |
function (arr, L)

But that [] is an ordinary object (thus with state), that can be modified as well. Now if the function can modify or return L, you start modifying the state of L. In the example:

def function(arr, L=[]):
    L.append(arr)
    return L

You modify L. If you call this the first time (for instance with function(123)), the object is updated so, now it is represented as:

               |-->  [123]
               |
function (arr, L)

As a result the behavior of function depends on a global state. In general a global state is seen as a bad smell in code design and furthermore it is not what people might expect. This doesn't hold for None, since you modify the local reference L (not the object itself).

You can say that the object is the same, but each time you call the function, you copy a reference to a local variable L.

Now for the second case:

                  |--> None
                  |
def function(arr, L):
    if L is None:
        L = []
    L.append(arr)
    return L

If you call this method, you assign a value to L, but L itself is not global (only the object to which L refers). So if you call this method, after the if, the function (in progress) will look like.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

Because the argument l is assigned an initial value of [] NOT when you call the function but when it's first declared and the module it's in is interpreted.

See: Python: Common Gotcha (Thanks @ferhat elmas)

Example: (showing what's going on)

$ python
Python 2.7.9 (default, Mar 19 2015, 22:32:11) 
[GCC 4.8.4] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def f(L=[]):
...     L.append(1)
...     return id(L), L
... 
>>> def g(L=None):
...     L = [] if L is None else L
...     L.append(1)
...     return id(L), L
... 

We'll ignore what happens when you pass in another list to the L argument because that behaviour is well defined and acceptable. (takes a list, appends to it and returns it).

>>> f()
(139978918901088, [1])
>>> g()
(139978918964112, [1])

The first time we call f() and g() we might mistakenly think that we have successfully returned a new list from an initial empty one right? What what happens when we call f() again compared with the correct g():

>>> f()
(139978918901088, [1, 1])
>>> g()
(139978918964112, [1])

So the initial value you assigned for the argument L is set once and only only when the function is defined; not when it's called. This is a common gotcha as explained in the link aove.

NB: id() here returns the unique identity of objects so you can clearly see why the first is an incorrect way to define a default value for a mutable object such as a list.

Also Note: In the above examples that the identity of L does not change when calling f().

James Mills
  • 18,669
  • 3
  • 49
  • 62