Reputation: 113
so i've run into a perplexing issue when utilising the dict.get() method in python in conjunction with a default of a dict[index]:
d = {1: 1}
d2 = {2: 2}
#throws KeyError
d.get(1, d2[1])
i'm a little lost on why this happens....in my mind the d2
index should never be called, given that the key 1 exists in d
. I'm guessing this is an implementation detail i'm missing and can't seem to find more info on.
Is there any help/hope for me?
Upvotes: 0
Views: 83
Reputation: 51093
d.get(1, d2[1])
is not a conditional/branching statement or expression like if
is, it is just a normal method call, so all of the code is evaluated unconditionally.
Before the get
method can be called, its arguments need to be evaluated. d2[1]
is the second argument, so this is evaluated - raising KeyError - before the method is called at all. So this is the expected behaviour, not an implementation detail.
To do what you want, you can use a conditional expression like below, which will only raise KeyError when neither dictionary has the key. The expression d2[1]
is not evaluated unless the condition is false, because the if
expression branches.
d[1] if 1 in d else d2[1]
Upvotes: 1
Reputation: 531718
The expressions used for the arguments to get
(or any function) must be evaluated before get
is ever called. Python doesn't have lazy evaluation semantics, and this is part of the language's definition, not an implementation detail of CPython.
Compare this with something like the defaultdict
type, which takes a callable that returns a default value, rather than the default value itself.
defaultdict(lambda: 3) # not defaultdict(3)
defaultdict(int) # not defaultdict(0); int happens to return
# 0 when called with no arguments.
get
, however, expects a value, not a function that can be called to produce a value.
Upvotes: 4