This question already has answers here:
Closed 4 years ago.
I was reading the python tutorial from Python Documentation Release 2.7.10 and I came across something like this.
Code
def fun1(a,L=[]):
L.append(a)
return L
print fun1(1)
print fun1(2)
print fun1(3)
def fun2(a,L = None):
if L is None:
L=[]
L.append(a)
return L
print fun2(1)
print fun2(2)
print fun2(3)
Output
[1]
[1, 2]
[1, 2, 3]
[1]
[2]
[3]
Process finished with exit code 0
If the L=[]
in the first function fun1()
is getting called only once , the output of fun1()
is fine. But then why L=None
is getting called every time in fun2()
.
When you define a function the values of the default arguments get evaluated, but the body of the function only get compiled. You can examine the result of the function definition via attributes. Theres a __defaults__
attribute containing the defaults and __code__
attribute containing the body (so these are created when the function is defined).
What's happening in the second example is that None
do get evaluated at definition (it evaluates to None
duh!), but the code that conditionally assigns []
to L
only gets compiled and is run each time (the condition passes).
L=[]
in the function declaration makes Python essentially do this:
- this function has a parameter named
L
- its default argument is
[]
, let's set this particular []
aside and use it anytime there's no parameter passed for L
- every time the function is called, create a variable
L
, and assign it either the passed parameter or the value we set aside earlier
So, the []
part is getting executed once, which creates a list object, which is set aside and kept around, which is why it accumulates changes if you modify it. Exactly the same thing happens with None
, however None
is not being modified nor is it mutable to begin with, so you're not seeing any weird side effects. None
is still only being "executed" once, and that particular None
value is set aside just as the list was, it's just that you're not doing anything to the None
value itself.
default arguments are evaluated only once. In fun1
you have the same list which you keep adding to. In fun2
you assign a new []
to the parameter and then append to it. As any assignment, its scope will be limited to the block it occurred in.