Issue with function keyword defaults

Ken Seehof kseehof at neuralintegrator.com
Sun Aug 5 14:36:38 CEST 2001


The default expression "{}" is evaluated only once, when the function
is defined.  The value of the expression is stored as a property of the
function object.  Thus the binding for r doesn't change, but it's value
is a dictionary, which is mutable.

The moral of the story is: mutable default arguments are dangerous.
Actually, mutable arguments in general are dangerous, unless you
know how they work.

What you need to do is this:

>>> def test(r={}):
...     r = r.copy()
...     r[time.time()] = time.time()
...     return r
...    
>>> test()
{997013843.75999999: 997013843.75999999}
>>> test()
{997013845.57000005: 997013845.57000005}
>>> test()
{997013846.88999999: 997013846.88999999}

Note that the copy also protects your dictionary argument from 
side effects if one is passed in.  In the original version you get:

>>> def test(r={}):
...     r[time.time()] = time.time()
...     return r
... 
>>> z = {'a':1}
>>> test(z)
{997014161.34000003: 997014161.34000003, 'a': 1}
>>> z
{997014161.34000003: 997014161.34000003, 'a': 1}

This may or may not be what you want, but "functional programming"
monks consider such things to be sacrilegious.  In fact, your example
should give functional programming monks a good reason to go find a
different language!  :-)

- Ken Seehof
kseehof at neuralintegrator.com
www.neuralintegrator.com/kseehof

From: "Morten W. Petersen" <morten at thingamy.net>
> Hi,
> 
> after trying to set an empty dictionary as a default keyword arguments'
> value, this happened (same thing happened on 2.0.1 BTW):
> 
> morten at debian:~$ python
> Python 1.5.2 (#0, Apr 10 2001, 10:03:44)  [GCC 2.95.3 20010219
> (prerelease)] on linux2 Copyright 1991-1995 Stichting Mathematisch
> Centrum, Amsterdam
> >>> import time
> >>> def test(r={}):
> ...     r[time.time()] = time.time()
> ...     return r
> ...
> >>> test()
> {997015577.922: 997015577.922}
> >>> test()
> {997015578.849: 997015578.849, 997015577.922: 997015577.922}
> >>> test()
> {997015579.446: 997015579.446, 997015578.849: 997015578.849, 
>  997015577.922: 997015577.922
> 
> I would assume that r would be re-initialized on every call, but that's
> not happening;  could anyone explain this behaviour?
> 
> Thanks,
> 
> Morten
> 
> -- 
> http://mail.python.org/mailman/listinfo/python-list

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20010805/f4c1f5f4/attachment.html>


More information about the Python-list mailing list