Reputation: 24500
I know this has been answered in highly active 'least astonishment' question, I modified code snippet slightly but still don't understand why it produces new empty list and adds 1 to it..
def foo(var=[]):
if len(var) == 0:
var = []
print(var)
var.append(1)
return var
print(foo())
print(foo())
outputs:
[]
[1]
[]
[1]
My expected logic of this python snippet:
on the first call of foo(), var is initialized to empty list and indeed - evaluated at definition of foo ONCE - as the popular question answered.
That if clause check should not be entered at all - because var is initialized only once, on the 2nd call foo() it should simply skip it and add 1 to var = [ 1 ] thus making the result [1,1] after the 2nd call.
But it does still go to if clause and init var to [] every time.. why?
However, if I remove the if clause:
def foo(var=[]):
print(var)
var.append(1)
return var
print(foo())
print(foo())
It does append "1" to var every time and var grows:
[1]
[1,1]
So the if clause is entered and checked for validity.. confused about the execution..
Upvotes: 1
Views: 88
Reputation: 8395
var=[]
on line 1 gets evaluated once when the function is defined
var=[]
on line 3 gets evaluated every time you pass a var with len(var) == 0
, for instance when you pass no args and the default is used.
This means that the []
on line 3 is a new list every time the function is called, as that line of code is executed every time the function is called.
Upvotes: 1
Reputation: 2016
alright, so the two things:
var
in your function definition is assigned to an empty list i.e []
that is good,var
in the if
statement is again being re-assigned but is the same thing, an empty list, this you don't really need as it's preventing you from achieving [1,1]
this may help clear things of why you're "expecting" a var = [1,1]
the first time around:
def foo(var=[]):
if len(var) == 0:
print(var)
var.append(1)
return var
print(foo()) # returns [],[1]
print(foo()) # returns [1,1] this list appended another 1 in because when you ran this instance of foo, this list was not empty anymore rather filled with 1 and bypassed the if statement and appended another 1 resulting to [1,1]
thus, you don't really need that var = []
in the if statement as it confuses the next steps as to what you want to achieve...
hope that helps somewhat :)
Upvotes: 1
Reputation: 402553
Let's rewrite your example so that we make some change to the argument before reassigning:
In [262]: def foo(var=[]):
...: var.append(1) # 1
...: print(var) # 2
...: var = [] # 3
...: return var # 4
...:
In [263]: foo()
[1]
Out[263]: []
In [264]: foo()
[1, 1] # reflects the append from the previous call
Out[264]: []
The append step in line 1 mutates the default argument list. The reassignment step in line 3 simply reassigns the variable var
to a new list (a completely different object), that's what you return.
You'll see each subsequent call modifies the default argument list, it's still there but you just don't see it because you lose the reference to it when you reassign.
I recommend reading this article by Ned Batchelder.
Upvotes: 2