Mutable default values for function parameters

sebastien s.keim at laposte.net
Thu Oct 4 04:56:00 EDT 2001


I'd like to point something that is said in §4.7.1 of the tutorial:

"Important warning: The default value is evaluated only once. This
makes a difference when the default is a mutable object such as a list
or dictionary"

I think that this point is really difficult to understand. That means
that parameters with mutable default value are global to all the calls
of the function:
>>> def sample(x,d=[]):
... 	d.append(x)
... 	print d
... 
>>> sample(1)
[1]
>>> sample(2)
[1, 2]

This is a really confusing and I always fall in this sort of trap.
Maybe a bad neuronal connection;-)

For sample I have tried to do something like Eiffel loop variant:

def variant(data, old_data=[None]):
	st = (data <> old_data[0])
	old_data[0] = data
	return st

for i in range(5):
	assert variant(i)
	print i
while i>0:
	assert variant(i)
	i -= 1
	
This fail because old_data remain the same between the last loop in
the for and the first one in the while.

I've seen the same problem in
http://www-106.ibm.com/developerworks/library/l-pycon.html?n-l-9271

   def randomwalk_static(last=[1]):    # init the "static" var(s)
       rand = random.random()          # init a candidate value
       if last[0] < 0.1:               # threshhold terminator
           return None                 # end-of-stream flag
       while abs(last[0]-rand) < 0.4:  # look for usable candidate
           print '*',                  # display the rejection
           rand = random.random()      # new candidate
       last[0] = rand                  # update the "static" var
       return rand

   def print_num():	
   	num = randomwalk_static()
   	while num is not None:
		print num,
		num = randomwalk_static()

The first call of print_numl work fine, but later calls will fail
because 'last' parameter will always contain a number <0.1

Maybe it would be better to have an alternate behavior for default
value creation. Instead of creating them at function definition, the
compiler could do the creation when it evaluate the function call. 
This will not be easy because of Python dynamism: the compiler doesn't
know function signature when it builds the call. And this is even
worse for object methods where the signature can be different for two
classes.

Or maybe, someone could give me an obvious way to solve this kind of
problems?

Thanks.



More information about the Python-list mailing list