e-mail address change (was Re: [Tutor] python's default argument value handling in functions - weird syntax? problem grappling with the concept)

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Wed Feb 9 23:05:23 CET 2005



On Thu, 10 Feb 2005, Jeffrey Lim wrote:
> > >
> > >Example 1
> > > >>> def f(a,L=[]):
> > >...     if L==[5]:
> > >...       print 'L==[5] caught'
> > >...       print L
> > >...       print 'resetting L...'
> > >...       L=[]
> > >...     L.append(a)
> > >...     return L
> > >...

Hi Jeffery,


At the beginning of a function call, if a function has default parameter
values, then the parameters get aimed at those default values.  So every
time through the call to f() here, L will initially refer to that list
value.



I liked your experiments in your earlier post.  Let's run through your
example, and see if our explanation matches with reality.  *grin*

To make talking abou this a little less confusing, do you mind if I change
the definition slightly, to this?

###
initialList = []

def f(a,L=initialList):
    if L==[5]:
        print 'L==[5] caught'
        print L
        print 'resetting L...'
        L=[]
    L.append(a)
    return L
###


It should have about the same effect as your previous code, but with the
advantage of letting us poke around at the list that's being used as the
default value.


Ok, let's try this out.

###
>>> f(5)
[5]
###

Ok, at this point, the 'default value' that initialList refers to should
also be [5].  Let's check this.

###
>>> initialList
[5]
###

Ok, good.



Now we call f(5) again:

###
>>> f(5)
L==[5] caught
[5]
resetting L...
[5]
###

The reassignment to L in the 'if' block:

    if L==[5]:
        print 'L==[5] caught'
        print L
        print 'resetting L...'
        L=[]

doesn't do any mutation on the actual default value.  L is just a name
that can be aimed at values: rebinding L through assignment doesn't
"mutate" the list value.  We'll talk about this again later in this post.


We can look at the default value again by peeking at it through
initialValue again:

###
>>> initialList
[5]
###

So if we call f() again, since L is always bound to the default value,



Let's call f(2) one more time.

###
>>> f(2)
L==[5] caught
[5]
resetting L...
[2]
###

Yup.  The reassignment of L still doesn't do anything to the value that L
is referring to, so subsequent calls to f() should continue to say
"resetting L".


Does this make sense so far?  Please feel free to ask questions on any
part that seems wacky, and we'll try to make sense out of it.  *grin*



Looking back at the program, I think that you meant to write:

###
initialList = []
def f(a,L=initialList):
    if L==[5]:
        print 'L==[5] caught'
        print L
        print 'resetting L...'
        del L[:]             ## Resets the initial value to the empty list
    L.append(a)
    return L
###


The change here is the commented line:

        del L[:]             ## Resets the initial value to the empty list

which causes the list that we refer to as "L" to shrink down to the empty
list.


There are a few tricky subtleties here, and we have to keep in mind the
distinction between a "name" and a "value".  'names' are like fingers that
point at 'values'.

Python handles default parameters by pointing the parameter name to a
default value when it enters a function.  So if we want to do things that
make the default parameter appear to "change", we have to mutate the value
that the parameter is pointed at.


Hope this helps!



More information about the Tutor mailing list