Python – ‘if foo in dict’ vs ‘try: dict[foo]’

python

This is less a question about the nature of duck typing and more about staying pythonic, I suppose.

First of all – when dealing with dicts, in particular when the structure of the dict is fairly predictable and a given key is not typically present but sometimes is, I first think of two approaches:

if myKey in dict:
    do_some_work(dict[myKey])
else:
    pass

And of course Ye Olde 'forgiveness vs permission' approach.

try:
    do_some_work(dict[myKey])
except KeyError:
    pass

As a journeyman Python guy, I feel like I see the latter preferred a lot, which only feels odd I guess because in the Python docs try/excepts seem to be preferred when there is an actual mistake, as opposed to an, um… absence of success?

If the occasional dict does not have key in myDict, and it is known that it will not always have that key, is a try/except contextually misleading? This isn't a programming error, it's just a fact of the data – this dict just didn't have that particular key.

This seems particularly important when you look at the try/except/else syntax, which looks to be really useful when it comes to making sure that try isn't catching too many errors. You're able to do something like:

try:
    foo += bar
except TypeError:
    pass
else:
    return some_more_work(foo)

Isn't that going to lead to swallowing all kinds of weird errors that are probably the result of some bad code? The above code might just be preventing you from seeing that you're trying to add 2 + {} and you may never realize that some part of your code has gone horribly wrong. I don't suggest that we should Check All The Types, that's why it's Python and not JavaScript – but again with the context of try/except, it seems like it's supposed to catch the program doing something it shouldn't be doing, instead of enabling it to carry on.

I realize the above example is something of a straw-man argument, and is in fact intentionally bad. But given the pythonic creed of better to ask forgiveness than permission I can't help but feel like it begs the question of where the line in the sand actually is between correct application of if/else vs try/except is, in particular when you know what to expect out of the data you're working with.

I'm not even talking about speed concerns or best practice here, I'm just sort of quietly confused by the perceived Venn diagram of cases where it looks like it could go either way, but people err on the side of a try/except because 'someone somewhere said it was Pythonic'. Have I drawn the wrong conclusions about the application of this syntax?

Best Answer

Use the get method instead:

some_dict.get(the_key, default_value)

...where default_value is the value returned if the_key is not in some_dict. If you omit default_value, None is returned if the key is missing.

In general, in Python, people tend to prefer try/except than checking something first - see the EAFP entry in the glossary. Note that many "test for membership" functions use exceptions behind the scenes.