On Thu, 04 Nov 2010 22:34:07 +0000, Mark Wooding wrote: > (Based on experience with other languages, I suspect that evaluating the > default expression afresh for each call where it's needed would be more > useful; but it's way too late to change that now.)
Let's call the two strategies: defaults initialise on function definition (DID) defaults initialise on function call (DIC) I claim that when designing a general purpose language, DID (Python's existing behaviour) is better than DIC: (1) most function defaults only need to be set once; (2) it's easy to get DIC if the language uses DID, but hard the other way; (3) DIC is needless wasteful for common function definitions; (4) DIC can lead to surprising bugs. That last isn't a big concern, since DID can lead to surprising bugs as well *wink*, but it's worth mentioning the failure mode. #1 Most default values are things like True, False, None, integer or string literals. Since they're literals, they will never change, so you only need to set them once. #2 It's easy to get default values to initialise on function call in a language that uses initialisation on function definition semantics: just move the initialisation into the function body. Python has a particularly short and simple idiom for it: def f(x=None): if x is None: x = some_expression() But if the situations were reversed, it's hard to get the DID semantics: def f(x=None): if x is None: global _f_default_arg try: x = _f_default_arg except NameError: _f_default_arg = x = default_calculation() #3 Re-initialising default values is wasteful for many functions, perhaps the majority of them. (Of course, if you *need* DIC semantics, it isn't wasteful, but I'm talking about the situations where you don't care either way.) In current Python, nobody would write code like this: def f(x=None, y=None, z=None): if x is None: x = 1 if y is None: y = 2 if z is None: z = 3 but that's what the DIC semantics effectively does. When you need it, it's useful, but most of the time it's just a performance hit for no good reason. A smart compiler would factor out the assignment to a constant and do it once, when the function were defined -- which is just what DID semantics are. If you're unconvinced about this being a potential performance hit, consider: def expensive_function(): time.sleep(30) # simulate a lot of computation return 1.23456789 def f(x=expensive_function()): ... What would you prefer, the default value to be calculated once, or every time you called f()? #4 Just as DID leads to surprising behaviour with mutable defaults, so DIC can lead to surprising behaviour: def f(x=expression): do_something_with(x) If expression is anything except a literal, it could be changed after f is defined but before it is called. If so, then f() will change it's behaviour. -- Steven -- http://mail.python.org/mailman/listinfo/python-list