Recipe 20.1. Getting Fresh Default Values at Each Function CallCredit: Sean Ross ProblemPython computes the default values for a function's optional arguments just once, when the function's def statement executes. However, for some of your functions, you'd like to ensure that the default values are fresh ones (i.e., new and independent copies) each time a function gets called. SolutionA Python 2.4 decorator offers an elegant solution, and, with a slightly less terse syntax, it's a solution you can apply in version 2.3 too: import copy def freshdefaults(f): "a decorator to 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) # in 2.4, only: refresher._ _name_ _ = f._ _name_ _ return refresher # usage as a decorator, in python 2.4: @freshdefaults def packitem(item, pkg=[ ]): pkg.append(item) return pkg # usage in python 2.3: after the function definition, explicitly assign: # f = freshdefaults(f) DiscussionA function's default values are evaluated once, and only once, at the time the function is defined (i.e., when the def statement executes). Beginning Python programmers are sometimes surprised by this fact; they try to use mutable default values and yet expect that the values will somehow be regenerated afresh each time they're needed. Recommended Python practice is to not use mutable default values. Instead, you should use idioms such as: def packitem(item, pkg=None): if pkg is None: pkg = [ ] pkg.append(item) return pkg The freshdefaults decorator presented in this recipe provides another way to accomplish the same task. It eliminates the need to set as your default value anything but the value you intend that optional argument to have by default. In particular, you don't have to use None as the default value, rather than (say) square brackets [ ], as you do in the recommended idiom. freshdefaults also removes the need to test each argument against the stand-in value (e.g., None) before assigning the intended value: this could be an important simplification in your code, where your functions need to have several optional arguments with mutable default values, as long as all of those default values can be deep-copied. On the other hand, the implementation of freshdefaults needs several reasonably advanced concepts: decorators, closures, function attributes, and deep copying. All in all, this implementation is no doubt more difficult to explain to beginning Python programmers than the recommended idiom. Therefore, this recipe cannot really be recommended to beginners. However, advanced Pythonistas may find it useful.
See AlsoPython Language Reference documentation about decorators; Python Language Reference and Python in a Nutshell documentation about closures and function attributes; Python Library Reference and Python in a Nutshell documentation about standard library module copy, specifically function deepcopy. |