Bizarre behavior with mutable default arguments

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Dec 29 19:27:33 EST 2007


On Sat, 29 Dec 2007 11:14:30 -0800, bukzor wrote:


> In python25 (this function from the FAQ linked above): 
> def f(a, _cache={}):
>     # Callers will never provide a third parameter for this function.
> (then why is it an argument?)

The caller might want to provide it's own pre-prepared cache. Say, for 
testing.

I think that this behaviour is a little unintuitive, and by a little I 
mean a lot. Nevertheless, I am used to it, and I don't see any reason to 
change it. There's very little about programming that is intuitive -- 
there's no intuitive reason to think that dictionary lookups are O(1) 
while list lookups are O(n).

In the absence of a better solution, I'm very comfortable with keeping 
the behaviour as is. Unfortunately, there's no good solution in Python to 
providing functions with local storage that persists across calls to the 
function:


(1) Use a global variable.

cache = {}
def foo():
    global cache
    print cache


(2) Use a function attribute.

def foo():
    print foo.cache
foo.cache = {}


def foo():
    try:
        foo.cache
    except AttributeError:
        foo.cache = {}
    print foo.cache



(3) Use an argument that isn't actually an argument.

def foo(cache={}):
    print cache


#1, the global variable, is probably the worst solution of the lot. 
Global variables are rightly Considered Harmful.


#2 has the disadvantages that you initialize the value *after* you write 
the code that relies on it. Either that, or you waste time on every call 
checking to see it if has been initialized. Also, like recursive 
functions, it is difficult to rename the function.


#3 is, I think, the least-worse solution, but I would hardly call it 
ideal.



> _cache = {}
> def f(a):
>     global _cache
>     ...
> 
> This follows the "explicit is better" and "one best way" principles of
> Python, 

Declaring an argument is equally explicit.

And you are confused -- the Zen doesn't say "one best way". People so 
often get it wrong.

The Zen says:

"There should be one-- and PREFERABLY only one --OBVIOUS way to do it."
(Emphasis added.)

At least you're not saying "there should be only one way to do it". I 
give you credit for that!


> and greatly improves the intuitiveness. Also since the first
> example is much more common, it reduces the overall verbosity of the
> language.

I question that it is "much more common". How do you know? Where's your 
data?



-- 
Steven



More information about the Python-list mailing list