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