Reputation: 18127
I've got some code (that someone else wrote):
def render(self, name, value, attrs=None):
if not attrs:
attrs = {}
attrs.update({'class': 'ui-autocomplete-input'})
which I think could be re-written as:
def render(self, name, value, attrs={}):
attrs.update({'class': 'ui-autocomplete-input'})
This would of course fail if someone passed in attrs=None
, but is that something to be expected? Is there a penalty for the attrs={}
(extra wasted dict creation?)
I'm still too new to python to answer these questions, but I am curious.
When I test this in the interpreter, I get:
>>> def x(attrs={}):
... attrs.update({'a': 'b'})
... print attrs
...
>>> x({'b': 'c'})
{'a': 'b', 'b': 'c'}
>>> x({'d': 'e'})
{'a': 'b', 'd': 'e'}
>>> x()
{'a': 'b'}
How does this ever cause a problem? Note that I'm ALWAYS adding that dict to the attrs, even if the user specified one (which may actually point to a different problem (I should probably merge the class attribute with an existing one if present).
------------------- And to point out the flaw in the above ------------------
>>> def yikes(attrs):
... attrs.update({'something': 'extra'})
... print attrs
>>> def x(attrs={}):
... print "Before:", attrs
... attrs.update({'a': 'b'})
... print "After:", attrs
... yikes(attrs)
>>> x({"b": "c"})
Before: {'b': 'c'}
After: {'a': 'b', 'b': 'c'}
{'a': 'b', 'b': 'c', 'something': 'extra'}
>>> x()
Before: {}
After: {'a': 'b'}
{'a': 'b', 'something': 'extra'}
Still seems ok, what's the problem?
>>> x()
Before: {'a': 'b', 'something': 'extra'}
After: {'a': 'b', 'something': 'extra'}
{'a': 'b', 'something': 'extra'}
Ahhh, now I get it, if {'something': 'extra'}
is added by some other bit of code, that never gets cleaned up. Sure, the attrs I force to be there are there, but so is the {'something': 'extra'}
that shouldn't be. This is subtle enough to be good fodder for an obfuscation contest, lookout PERL!
Upvotes: 8
Views: 195
Reputation: 176980
Yes. Default arguments are evaluated at function definition time. If you use a mutable default argument, it will always be the same one. So once you modify attrs
, it will stay modified.
Upvotes: 2
Reputation: 11554
The problem is the dictionary is created once at function definition, so all calls use the same dictionary. This is usually NOT the intended behavior, hence the tendency for folks to use the =None version.
Upvotes: 2
Reputation: 21460
I guess that since your signature specifies attrs={}
all users will either provide a dict or won't use this field, making it be {}
. Thus, in this case it is almost impossible for someone to pass None
- in that case it's their fault. However, in this case the dict will be updated across several calls, maybe you don't want this.
Always use sensible defaults when using defaults.
Upvotes: 1
Reputation: 29740
Using attrs = {}
in the function signature will bite you, since it will keep its value on successive calls to the function. The original code is best.
eg.
>>> def a(attrs= {}):
... print attrs
... attrs.update({1:1})
...
>>> a()
{}
>>> a()
{1: 1}
Note how it kept the value assigned the first time, on the second call.
Upvotes: 13