52

I am a python beginner, reading 'python tutorial', it says if we have a function:

def f(a, L=[]):
     L.append(a)
     return L
print f(1)
print f(2)
print f(3)

This will print

[1]
[1, 2]
[1, 2, 3]

Because the default value is evaluated only once and list is a mutable object. I can understand it.

And it says continue, if we don't want the default to be shared between subsquent calls, we can:

def f(a, L=None):
   if L is None:           #line  2
       L = []            
   L.append(a)
   return L
print f(1)            
print f(2)
print f(3)

and this will output:

[1]
[2]
[3]

But why? How to explain this. We know default value is evaluated only once, and when we call f(2), L is not None and that if(in line 2) can not be true, so L.append(a) == [1, 2]. Could I guess the default value is evaluated again for some reason , but what is 'some reason', just because the python interpreter see if L is None: L = []

Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
Feng Gang
  • 597
  • 1
  • 5
  • 10
  • 2
    I'm actually not sure if the dup applies. I think the OP understands the mutable default argument, but not why the second example works as it does. – Doug T. Oct 26 '12 at 13:01
  • @DougT.: and what OP is asking has then nothing at all to do with default arguments, does it? – SilentGhost Oct 26 '12 at 13:21
  • @SilentGhost It has to do with default arguments alright, but that does not make it a duplicate that asks a different thing about default arguments. The answers in that question don't address the confusion OP apparently has, as the question is a different one. –  Oct 26 '12 at 13:26
  • Seems to me like a very poor design choice in Python – Jimbali Sep 23 '22 at 09:35

5 Answers5

44

Python passes parameters to functions by value; So for objects, the value passed is a reference to the object, not a new copy of the object.

That, along with the following part of the official docs is what helped me understand it better (emphasis mine):

Default parameter values are evaluated [...] when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same “pre-computed” value is used for each call. This is especially important to understand when a default parameter is a mutable object, such as a list or a dictionary: if the function modifies the object (e.g. by appending an item to a list), the default value is in effect modified. [...] A way around this is to use None as the default, and explicitly test for it in the body of the function [...]

Putting it all together:

If you define the default for a parameter to be a mutable object (such as []) then the "pre-computed" value is the reference to that object, so each call to the function will always reference the same object, which can then be mutated across multiple invocations of the function.

However, since None is an immutable built-in type, the "pre-computed" value for a default of None is simply that. So the parameter will be None each time you call the function.

Hopefully that helps! I do think that the tutorial could have had better wording, because I was also confused by that at first.

Brenden Kromhout
  • 4,607
  • 1
  • 16
  • 13
  • 2
    Compared to the highest voted one, this is more clear to me. – ZijunLost Nov 04 '16 at 18:15
  • 1
    `def f(a, L=[]): if L == []: L = [] L.append(a) return L` has the same behavior of op's second case. `[]` is mutable, so what happened here ? – Rowan Sep 24 '17 at 06:27
  • 1
    For anyone confused about @Rowan's case: In the if statement, L is assigned to a new array with a new reference, but the default value for L in f is still the reference to the original array. – alphacapture Sep 14 '18 at 11:30
21

"The default value is only evaluated once" does not mean that a parameter with a default retains its value between invocations of the function. It means that the expression which you specify (the None part of def f(a, L=None)) is evaluated once, and the object it results in is stored in a hidden location and re-used if no value for that parameter is given at call. Parameters are still reset to the value (default or not) at every invocation.

  • 1
    This should be marked as accepted, great crystal clear answer. – laurids Jun 26 '15 at 13:11
  • great answer, thanks – Bin Jan 20 '16 at 13:11
  • 2
    I think it wasn't a good decision by Python team! For example we had a parameter with the default value to `datetime.now()`. This caused the default parameter to be the app start time not really now() which is really confusing. Some languages may sometimes surprise the developers but python usually tries no to. – mtoloo Mar 05 '20 at 06:28
3

In your second example you have a variable L. At first L refers to None. You repoint it to a new empty list on each invocation, then mutate that new list. Remember L = [] is the same as L = list()

In your first example, however, L is set to the new list once at function declaration. L isn't reset to [] on each invocation of the function. So you are always mutating the same list.

Doug T.
  • 64,223
  • 27
  • 138
  • 202
  • 2
    At first L refers to None, it repoint to a new empty list on first invocation not each invocation, because after once, L is not None and if statement can not be evaluated. – Feng Gang Oct 26 '12 at 13:55
3

What happens is as follows:

When a python function is called, it is evaluated in the environment in which it was defined and not the environment in which it was called although the second part is secondary ( no pun intended) for the purpose of answering your question.

The default arguments are evaluated only once at the time of function definition. This creates a closure. Think of closure as function code + environment in which the function was been defined.

So in this case when the function was defined, L was assigned to [] and now every subsequent call to the function will use this value of L.

The tutorial also mentions:

The default values are evaluated at the point of function definition in the defining scope (and the defining scope is part of the closure along with function code)

http://docs.python.org/2/tutorial/controlflow.html#default-argument-values

Ankur Agarwal
  • 23,692
  • 41
  • 137
  • 208
3

I think this is happening because a list is a mutable object while the value None is immutable.

For the first function, variable L is outside the function environment (in the function definition), and it refers to an empty list. Then you make changes to this list in the function environment, but since a list is mutable, the variable L that is outside the function environment refers to this now mutated list, and the change propagates each time you call the function.

For the second function, variable L is also outside the function environment (in the function definition), but this time it refers to None, which is immutable. Now, every change you make in the function environment will not affect what L refers to outside the function environment. The variable L inside the function environment refers to something different as you change it. First, it refers to an empty list, and then a list that gets a value appended to it. You then return this list. The next time you call the function, you call it with the variable L that is outside the function environment, which has not changed and still refers to None.

Hope this makes sense.

zk86
  • 31
  • 1