newbie question on Python tutorial example in section 4.7.1 (default arg values)

Rich Krauter rmkrauter at yahoo.com
Sun May 2 13:07:15 EDT 2004


On Sat, 2004-05-01 at 17:37, Porky Pig Jr wrote:
> Hello,
> hope someone can clarify this section for me (or may be there is a
> 'newbie FAQs' in which case I would appreciate the link
> 
> Anyway, the example is
> 
> def f(a, L=[]):
>     L.append(a)
>     return L
> 
> and somehow L just keeps growing between the calls, so
> 
> print f(1) 
> returns [1]
> and then
> print f(2)
> returns [1, 2]
> etc. I'm not really clear on this example, but assume that L is set
> aside somewhere (in the function definition), initialized only once
> (during the def), and then all subsequent calls affect that locally
> defined L.
> 
> Given this is how it works (?), I still don't understand how the
> following workaround works:
> 
> def f(a, L=None):
>     if L is None:
>         L = []
>     L.append(a)
>     return L
> 
> well, it does work, but why? Seems like we initialize L to None (which
> is as I undersatnd, sort of equivalent of C void), in fact it also
> works if we initialize L to some arbitrary string. What I don't
> understand: we check if
> L is None, and then make it a list and append 'a' to it. So it becomes
> a list. When then on the subsequent call it is None again rather than
> list with a single value of 'a' (in the previous call)?
> 
> TIA


Not sure if this will help you, and my description may not be entirely
accurate, but it helps me to remember that a function is a an object
with attributes. One of the attributes of a function object is called
func_defaults, which contains, suprisingly enough, a tuple of function
defaults: 

(as you said, "L is set aside somewhere")

>>> def func(a,L=[]):
	L.append(a)
	print L

	
>>> dir(func)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__module__',
'__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__str__', 'func_closure', 'func_code', 'func_defaults',
'func_dict', 'func_doc', 'func_globals', 'func_name']

>>> func.func_defaults
([],)
>>> func(1)
[1]
>>> func.func_defaults
([1],)
>>> func(2)
[1, 2]
>>> func(3)
[1, 2, 3]
>>> func.func_defaults
([1, 2, 3],)

This happens because L (the list at func.fun_defaults[0]) is mutable.
Every call to func appends a value to that list in its func_defaults
tuple. 

If L is instead made immutable in the function def, you see different
behavior:

>>> def func2(a,L=None):
	if L is None:
               # rebind [] to the name L, but not             
               # to func2.func_defaults[0]
	    L = []
	L.append(a)
	print L

	
>>> func2(1)
[1]
>>> func2.func_defaults
(None,)
>>> func2(2)
[2]
>>> func2.func_defaults
(None,)
>>> func2(3,L=[1,2,3])
# rebind [1,2,3] to the name L, but not to func2.func_defaults[0]
[1, 2, 3, 3]
>>> func2.func_defaults
(None,)

Hope that helps. 

Rich




More information about the Python-list mailing list