pythonshort-circuiting

dict.pop or dict.get and evaluation


Consider the following code:

>>> def default_answer():
...     print "Default was required!"
...     return 100
... 
>>> g = { 'name': 'Jordan', 'age': 35 }
>>> result = g.get('age', default_answer())
Default was required!
>>> result = g.pop('age', default_answer())
Default was required!

Notice that whether g contains the expected key or not, default_answer is called. This makes sense programmatically but if default_answer was computationally expensive this would be a hassle (to run a lot of code to create a value that was going to be thrown away).

The only way I can think of writing this without always calling default_answer is:

result = g.pop('age', False) or default_answer()

Is this the best way to do it?

(Note that I'm aware that replacing default_answer with an object with lazy evaluation would also solve part of this problem, but that's outside the scope of this question).


Solution

  • No, this is not the best way to do this, since the result of g.pop() might be "falsy". Use try/except instead:

    try:
        result = g.pop('age')
    except KeyError:
        result = default_answer()
    

    This idiom is called EAFP and is usually preferred over LBYL for various reasons:

    1. It avoids looking up the key twice (which is not an issue with an actual dict, but might be suboptimal with other mappings).

    2. It avoids a race condition in threaded code.

    3. Many people find it easier to read.