'dict.get() - default arg evaluated even upon success

Why is the default in dict.get(key[, default]) evaluated even if the key is in the dictionary?

>>> key = 'foo'
>>> a={}
>>> b={key:'bar'}
>>> b.get(key, a[key])
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    b.get(key, a[key])
KeyError: 'foo'


Solution 1:[1]

As in any function call, the arguments are evaluated before the call is executed.
In this case dict.get() is no exception...

Solution 2:[2]

use this instead

x = b.get(key) or a.get(key)

or and and are short circuit operators, so if b has the key it won't look at a. But problems will arise if you have false values in b. If that is the case you can do:

x = b[key] if key in b else a.get(key)

Solution 3:[3]

You can rewrite the example you gave as

b.get(key, a.get(key))

to avoid the exception. This will return None if the key is in neither dictionary. More generally, if you want to avoid the evaluation of the second argument, you could use

try:
    x = b[key]
except KeyError:
    x = a[key]   # or whatever the default value is supposed to be

Solution 4:[4]

Because you are evaluating it, then passing it as an argument to get. This happens whether or not get ends up using the argument.

Solution 5:[5]

To avoid the lookup you could:

value = b.get(key)
if value is None:
   value = a[key]

Or if None is allowed then:

not_set = object()
# ...
value = b.get(key, not_set)
if value is not_set:
   value = a[key]

Solution 6:[6]

  1. a[key] is a['foo'] and you don't have that key in a.
  2. this is evaluated before calling b.get hence the error
  3. "even if the key is in the dictionary" - that's anot true, b is empty (but as the 2. points shows, this is not relevant)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jonathan Livni
Solution 2 Bill
Solution 3 Sven Marnach
Solution 4 Day
Solution 5 jfs
Solution 6 Karoly Horvath