dict.get(key, default) evaluates default even if key exists

Chris Angelico rosuav at gmail.com
Tue Dec 15 18:10:36 EST 2020


On Wed, Dec 16, 2020 at 10:03 AM dn via Python-list
<python-list at python.org> wrote:
>
> On 16/12/2020 07:52, Dan Stromberg wrote:
> ...> BTW, I tend to prefer collections.defaultdict over the two argument
> D.get
> > or setdefault.
>
>
> Contrarily, dict.get() seems 'better', unless (a) the dict's values are
> all to be initialised to the same value, eg all None, int 0, or empty
> list []; or (b) my fingers will be tired by the number of dict.get()
> calls to be typed.
>
> This thought partly because it may be some 'distance' between the
> definition of the 'dict' as a defaultdict cf the built-in 'original',
> and therefore a simple boy (like me) finds it easy to forget or 'lose
> track'.
>
> Also, because it is unusual to come-across a default-factory which
> initialises values to the defaultdict other than uniformly.
>
> Have you seen any application of defaultdict with some more-complex and
> cleverly-designed default-factory function?
>
> Other than personal-preference (which should be respected), and a
> uniform default-value, what is the rationale for defaultdict over
> dict.get()?

It depends on use-case. Using dict.get() is appropriate when you want
to know if something's there without prepopulating it; but if your
entire purpose is to then stash something into the dict, and you'll
ALWAYS be following the same pattern, then it's often more convenient
to use __missing__. And if your __missing__ method is, as it commonly
will be, constructing a brand new object, then it's easiest to use
defaultdict. But a defaultdict for integers might be better written as
a Counter instead. There are a lot of similar options, and you take
whatever's easiest for this particular job.

One VERY common use-case is gathering things together into lists based
on some sort of lookup key. This one is perfect for defaultdict:

messages = defaultdict(list)
for msg in get_messages():
    messages[msg["author"]].append(msg)

That'll quickly and easily group the messages by their authors. The
first time an author is found, a new list is created, and then you
append them all.

(In digging for examples, I actually found a place where I'd used
defaultdict(collections.Counter) to create a nested structure very
easily. Worked out well. Pretty unusual thing to want though!)

ChrisA


More information about the Python-list mailing list