functions, list, default parameters

Dave Angel davea at ieee.org
Fri Oct 22 07:59:11 EDT 2010


On 2:59 PM, Sean Choi wrote:
> I found two similar questions in the mailing list, but I didn't understand
> the explanations.
>
> I ran this code on Ubuntu 10.04 with Python 2.6.5.
>
> Why do the functions g and gggg behave differently? If calls gggg(3) and
> g(3) both exit their functions in the same state, why do they not enter in
> the same state when I call gggg(4) and g(4)?
>
>
>
> # ---------------------------------------------------------------------- my
> code:
> def gggg(a, L=[]):
>      print "enter function"
>      print "a = ", a, "and L = ", L
>      if L == []:
>          print "hey, L is empty"
>          L = []
>      L.append(a)
>      print "after append, L = ", L
>      return L
>
> def g(a, L=[]):
>      print "enter function"
>      print "a = ", a, "and L = ", L
>      if L == []:
>          print "hey, L is empty"
>      L.append(a)
>      print "after append, L = ", L
>      return L
>
> print gggg(3)
> print gggg(4)
> print gggg(7)
> print g(3)
> print g(4)
> print g(7)
>
>
>
> # ---------------------------------------------------------------------- my
> output:
> -------------------gggg calls
> enter function
> a =  3 and L =  []
> hey, L is empty
> after append, L =  [3]
> [3]
> enter function
> a =  4 and L =  []
> hey, L is empty
> after append, L =  [4]
> [4]
> enter function
> a =  7 and L =  []
> hey, L is empty
> after append, L =  [7]
> [7]
> -------------------g calls
> enter function
> a =  3 and L =  []
> hey, L is empty
> after append, L =  [3]
> [3]
> enter function
> a =  4 and L =  [3]
> after append, L =  [3, 4]
> [3, 4]
> enter function
> a =  7 and L =  [3, 4]
> after append, L =  [3, 4, 7]
> [3, 4, 7]
>
You deserve a better answer than "Don't do that."  That is good advice, 
but if I were asking, I'd want a clearer explanation of what's going on.

In the g() function, you are seeing the effect that when a mutable 
object is used as a default parameter, it's shared among all uses of the 
function.  So each time you enter the function, you get the value the 
object had when the function was last exited.

It's important to point out that the behavior is the same for a 
immutable object, but since it can't be changed, nobody cares.  The 
immutable object will have the same value it was first created with.

So the secondary question is why function gggg() seems to have different 
behavior.  I haven't seen any responses that addressed that.

The answer is that gggg() doesn't change the original object.  Every 
time through the function, the local attribute L is bound to a new empty 
list, different from the one that was the default argument.  And it's 
the new one that's modified, and returned.  The original empty object is 
still there, to be used the next time the function is called.

The problem many new Python programmers have is to separate the notion 
of the symbol L and the object.  L is *not* a container for the list 
object, it is simply bound to it.  And the empty list object lives on 
even when you bind L to a different one.

Perhaps it'd help to print id(L) before and after the assignment, in 
function gggg().  After the assignment, L is bound to a new object, with 
a different id.  That new object is appended to, returned, and printed. 
Then it's thrown away.  Next time through the function, the original 
object is used for default argument.

If you needed to empty a list in-place, without changing to a new 
object, you could use
    L[:] = []


DaveA




More information about the Python-list mailing list