dict.setdefault() (Patch#101102) (was: Re: [Python-Dev] Re: A small proposed change to dictionaries' "get" method...)
Tim Peters
tim_one@email.msn.com
Mon, 7 Aug 2000 23:44:05 -0400
> artcom0!pf@artcom-gmbh.de:
> > dict.setdefault('key', [])
> > dict['key'].append('bar')
>
[Greg Ewing]
> I would agree with this more if it said
>
> dict.setdefault([])
> dict['key'].append('bar')
Ha! I *told* Guido people would think that's the proper use of something
named setdefault <0.9 wink>.
> But I have a problem with all of these proposals: they require
> implicitly making a copy of the default value, which violates
> the principle that Python never copies anything unless you
> tell it to.
But they don't. The occurrence of an, e.g., [] literal in Python source
*always* leads to a fresh list being created whenever the line of code
containing it is executed. That behavior is guaranteed by the Reference
Manual. In that respect
dict.get('hi', [])
or
dict.getorset('hi', []).append(42) # getorset is my favorite
is exactly the same as
x = []
No copy of anything is made; the real irritation is that because arguments
are always evaluated, we end up mucking around allocating an empty list
regardless of whether it's needed; which you partly get away from via your:
The default "value" should really be a thunk, not
> a value, e.g.
>
> dict.setdefault(lambda: [])
> dict['key'].append('bar')
>
> or
>
> dict.get_or_add('key', lambda: []).append('bar')
except that lambda is also an executable expression and so now we end up
creating an anonymous function dynamically regardless of whether it's
needed.
> But I don't really like that, either, because lambdas look
> ugly to me, and I don't want to see any more builtin
> constructs that more-or-less require their use.
Ditto.
> I keep thinking that the solution to this lies somewhere
> in the direction of short-circuit evaluation techniques and/or
> augmented assignment, but I can't quite see how yet.
If new *syntax* were added, the compiler could generate short-circuiting
code. Guido will never go for this <wink>, but to make it concrete, e.g.,
dict['key']||[].append('bar')
count[word]||0 += 1
I found that dict.get(...) already confused my brain at times because my
*eyes* want to stop at "[]" when scanning code for dict references.
".get()" just doesn't stick out as much; setdefault/default/getorset won't
either.
can't-win-ly y'rs - tim