The Association of Mad Scientists

A brief note on Dict accessing in Python

When I first started writing Python, almost every example I saw said to use the try...except method of dealing with absent keys in Dicts. I've been writing primarily in Crystal lately, which in its documentation suggests that exception catching is discouraged due to the performance hit it takes on. The standard API in Crystal also offers many ways of returning nil (a falsey value), rather than throwing an exception. Of course, there are still times where raising and catching an exception is still appropriate, but 95% of the time you can handle it with a default value or by returning an error case rather than raising an error. Golang also takes this route, although it's much more insistent about it, as panics don't come with a traceback and errors are usually returned as pointers of error type.

All that to say, I was wondering about how that might apply to Python, which, as I said, almost always recommends the try...except method for handling errors. So I wrote a little script and you won't be surprised by the results:

fastest took 458.13740929588675ns per operation
source:
# my personal choice
return (test_object.get('d') or 4) == 4


fast took 436.84498174116015ns per operation
source:
return test_object.get('d', 4) == 4


slow took 730.6549698114395ns per operation
source:
try:
    test_object['d']
    return False
except KeyError as e:
    if KeyError:
        return True

The above is the output of the script defined here. As you can see, using either the get() method of a Dict's default option, or, my preference: dict.get('expected') or 'default' which does the same thing in around the same amount of time. I would like the get() two-argument version just as much, that particular function doesn't do named-arguments, so you can't do dict.get('expected', default='default'). Oh well, no language or framework is perfect.