Default arguments, object sharing, name lookup and others

anton muhin antonmuhin at rambler.ru
Mon Dec 22 11:30:44 EST 2003


Maciej Sobczak wrote:
> Hi,
> 
> Playing around with the Python Tutorial I found the following definition:
> 
> def f(a,L=[]):
>     L.append(a)
>     return L
> 
> then:
> 
> f(1)
> f(2)
> f(3)
> 
> will accumulate the values appending them to the *same* list.
> 
> Now:
> 
> def f(a,s=''):
>     s = s + a
>     return s
> 
> f('hello')
> f('world')
> 
> This will not cause value accumulation.
> Interestingly, this will neither:
> 
> def f(a,L=[]):
>     L = L + [a]
>     return L
> 
> which is most confusing for me.
> 
> I do not understand how this works (the first one).
> I would like to ask you for some explanation, especially:
> - where is the object stored if it is shared between subsequent calls? 
> how it is found?
> - why does it work for lists and not for strings?
> - why does it work for lists only when the append method is used?
> 
> My "native" language is C++. Feel free to use analogies, where appropriate.
> 
> Thank you very much for any light,
> 
It' one of most famous Python's traps. Consider the following:

def foo1(a, L = []):
     print id(L)
     L = L + [a]
     print id(L)
     return L

def foo2(a, L = []):
     print id(L)
     L.append(a)
     print id(L)
     return L

def foo3(a, L = ''):
     print id(L)
     L += a
     print id(L)
     return L

print 'foo1'
foo1('a')
print

print 'foo2'
foo2('a')
print

print 'foo3'
foo3('a')
print

id returns an object's id, usually it's an address.
The code produces:

foo1
8276816
8276848

foo2
8276144
8276144

foo3
7774264
7919296

You can note, that only foo2 doesn't change L's id. That's the 
problem---each call populates the same L.

In more details:

L = L + [a] creates a new list
L.append(a) modifies a list in-place
s = s + a creates a new string. BTW, strings in Python are immutable.

How to cope with it. First of all, immutable default parameters 
prefered. If you need a mutable one, usual trick is somehting like this:

def foo(a, L = None):
   if L is None:
     return [a]
   else:
     return L + [a]

Or, in most of the cases, shorter:

def foo(a, L = None):
   return (L or []) + [a]

For more information you can search the group---this question is really 
popular one ;)

regards,
anton.





More information about the Python-list mailing list