Welcome, guest | Sign In | My Account | Store | Cart

This recipe provides a decorator for keeping mutable default function values fresh between calls.

Python, 18 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from copy import deepcopy

def freshdefaults(f):
    "wrap f and keep its default values fresh between calls"
    fdefaults = f.func_defaults
    def refresher(*args, **kwds):
        f.func_defaults = deepcopy(fdefaults)
        return f(*args, **kwds)
    return refresher

# usage, python 2.4+
@freshdefaults
def packitem(item, pkg=[]):
    pkg.append(item)
    return pkg

# for older python versions, 
# use f = freshdefaults(f)

In Python, a function's default values are evaluated once, and only once, at definition time. Beginning Python programmers are often caught out by this distinction when they try to use mutable default values, e.g., lists, dicts, etc. [1][2]

The recommended practice is to not use mutable default values. Instead, you should use the following idiom:

<pre> def packitem(item, pkg=None): if pkg is None: pkg = [] pkg.append(item) return pkg </pre>

The freshdefaults() decorator provides another way to accomplish the same task. It removes the need to declare your default value with something other than the value you intend it to have (None rather than []). It also removes the need to test against the stand-in value before assigning the intended value (which could be of benefit, were you to need several mutable default arguments).

At the same time, however, it adds a layer of indirection to the code and it introduces concepts (decorators, closures, function attributes, deep copying) that will likely be more difficult to explain to beginning Python programmers than is the recommended idiom.

[1] http://www.python.org/doc/faq/general.html#why-are-default-values-shared-between-objects

[2] http://zephyrfalcon.org/labs/python_pitfalls.html

Created by Sean Ross on Sat, 4 Sep 2004 (PSF)
Python recipes (4591)
Sean Ross's recipes (8)

Required Modules

Other Information and Tasks