[Tutor] python's default argument value handling in functions -weird syntax? problem grappling with the concept

Alan Gauld alan.gauld at freenet.co.uk
Wed Feb 9 23:32:07 CET 2005


> This leads me to at first conclude several things:
>
> 1. 'L' in this case (or by extension, all function arguments for
which
> a default is given in the function definition) is "static"

Pretty close, yes. Especially if the parameter is mutable.

> language definition). This is my conclusion, seeing as how 'L' can
> seem to retain its value even though it has gone out of scope after
> the 'f' function returns.

Thats right, the default value is evaluated once only,
it keeps that initial value for all future invocations.
But if it is mutable the list object(in the example)
is the same list but the content of the list can be
changed on each invocation.

> 2. (*Now this is where I start to get confused. I think the best way
> to illustrate how I am having problems is to illustrate with a few
> examples. The basic problem that I am having is, "Which L is which
> L?")
>
> My examples...
>
> Example 1
> >>> def f(a,L=[]):
> ...     if L==[5]:
> ...       print 'L==[5] caught'
> ...       print L
> ...       print 'resetting L...'
> ...       L=[]

Here you reassign L to a completely new list, but the original
default one is still lurking i the background complete with
the changes you made earlier.

> ...     L.append(a)
> ...     return L

You now return your new list.

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


> >>> f(2)
> L==[5] caught

So we go back to the original default

> [5]
> resetting L...

And you create another new list
> [2]

And return it.

> Example 2
> >>> def f(a,L=None):
> ...     if L==[5]:
> ...             print 'caught, printing, resetting'
> ...             print L

Should never happen unless you call f(a,[5])
that is never triggered for the default value.

> ...             L=[]

but now creates a brand new L regardless of what was
passed in

> ...     else:
> ...             L=[]

Create another new L

> ...     L.append(a)
> ...     return L

And modify and return the new list.

> ...
> >>> f(5)
> [5]
> >>> f(6)
> [6]

So in both cases you return a new list, the original
default None is still there but you ignore it!


> So when the default value for 'L' is an empty list, the test
> condition, _once triggered_, *always* catches?

No, it only catches if you pass in a value otherwise the
default will still be None. Notice your if branch was not
executed in either case above, only the return value is shown.

> But when the default value for 'L' is none, the 'if' never catches?

Because the default is None, the if only catches if you
override the default with a matching list.

> Or even consider the example given -
> def f(a, L=None):
>     if L is None:
>         L = []
>     L.append(a)
>     return L
>
> How is 'L == None' even possible all the time, given that for

Because the value is only evaluated *once*. The default is set
forever to None which is *immutable* - you cant change it,
only overwrite it.

> def f(a, L=[]):
>     L.append(a)
>     return L
> , L isn't even [] except for the first call to 'f'?

The value is set only once, the list is created and the same
list object is used each time. But because list objects are
*mutable* you can change the *contents* of the list, but you
can never change the default list itself.

Its just as the docs say. BUt don;t try to hard to think in
terms of C. This is Python not C and it works differently.
In C parameters etc are locations on the memory stack.
In Python they are entries in a dictionary. Very different
concepts and they result in very different behaviour!

HTH,

Alan G
Author of the Learn to Program web tutor
http://www.freenetpages.co.uk/hp/alan.gauld



More information about the Tutor mailing list