55

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 = []

4
  • 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. Commented Oct 26, 2012 at 13:01
  • @DougT.: and what OP is asking has then nothing at all to do with default arguments, does it? Commented Oct 26, 2012 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. Commented Oct 26, 2012 at 13:26
  • Seems to me like a very poor design choice in Python Commented Sep 23, 2022 at 9:35

5 Answers 5

48

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Compared to the highest voted one, this is more clear to me.
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 ?
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.
23

"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.

3 Comments

This should be marked as accepted, great crystal clear answer.
great answer, thanks
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.
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.

1 Comment

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.
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

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.