Pythonic way for missing dict keys

Carsten Haese carsten at uniqsys.com
Fri Jul 20 21:31:18 CEST 2007


On Fri, 2007-07-20 at 19:08 +0000, Alex Popescu wrote:
> Hi all!
> 
> I am pretty sure this has been asked a couple of times, but I don't seem 
> to find it on the archives (Google seems to have a couple of problems 
> lately).
> 
> I am wondering what is the most pythonic way of dealing with missing 
> keys and default values.
> 
> According to my readings one can take the following approaches:
> 
> 1/ check before (this has a specific name and acronym that I haven't 
> learnt yet by heart)
>
> if not my_dict.has_key(key):
>   my_obj = myobject()
>   my_dict[key] = my_obj
> else:
>   my_obj = my_dict[key]

This is called "Look before you leap." Note that "if key in my_dict" is
preferred over has_key().

> 2/ try and react on error (this has also a specific name, but...)
>
> try:
>   my_obj = my_dict[key]
> except AttributeError:
>   my_obj = myobject()
>   my_dict[key] = my_obj
> 

This is called "It's easier to ask for forgiveness than permission."

> 3/ dict.get usage:
> 
> my_obj = my_dict.get(key, myobject())
> 
> I am wondering which one is the most recommended way? get usage seems 
> the clearest, but the only problem I see is that I think myobject() is 
> evaluated at call time, and so if the initialization is expensive you 
> will probably see surprises.

All ways are equally acceptable. The main difference is in the amount of
optimism the code conveys about the existence of the key. Number 1 and 3
convey the notion that you expect the key to be missing, that it's
normal for the key to be missing. Number 2 conveys the notion that the
key is only missing under exceptional circumstances.

As you noted, number 3 is not good if it's expensive to initialize a
myobject() instance, because the object will be created regardless of
whether it'll be needed. In that case, you should go with number 1, or
the following variant of number 3:

my_obj = my_dict.get(key, None)
if my_obj is None: my_obj = myobject()

This only works if the dictionary doesn't contain Nones already. If it
does, you would create a cheap sentinel object instead:

sentinel = object()
my_obj = my_dict.get(key, sentinel)
if my_obj is sentinel: my_obj = myobject()

HTH,

-- 
Carsten Haese
http://informixdb.sourceforge.net





More information about the Python-list mailing list