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