dict.get(key, default) evaluates default even if key exists
Roel Schroeven
roel at roelschroeven.net
Sat Dec 19 16:29:34 EST 2020
Ethan Furman schreef op 16/12/2020 om 17:59:
> Or, if the computationally massively expensive call uses potentially
> different arguments for each invocation:
>
> some_var = d.get('a') or cme(arg1, arg2, ...)
I don't like that because it is very fragile: the expression will
evaluate to the second part not only when 'a' is not in the dictionary
but also whenever the value corresponding to key 'a' is false-y.
Example:
def slow_function(a, b):
# Pretend this is slow, or there is any other reason for this
# function to be called only when strictly necessary.
print('slow_function called')
return a + b
d = {
'spam': 0,
'ham': 1,
'parrot': 2,
}
some_var = d.get('spam') or slow_function(31, 11)
print(some_var)
Result: slow_function is called, and some_var equals 42 instead of 0.
You could make it work reliable by using a unique sentinel value and the
walrus operator:
SENTINEL = object()
some_var = (
r
if (r := d.get('spam', SENTINEL)) is not SENTINEL
else slow_function(31, 11)
)
But I don't like that either because it's way too complicated.
What could be useful in some use cases, I think, is a wrapper function
that evaluates the function lazily:
def dict_get_lazily(d, key, fnc, *args, **kwargs):
try:
return d[key]
except KeyError:
return fnc(*args, **kwargs)
some_var = dict_get_lazily(d, 'spam', some_function, 31, 11)
--
"Honest criticism is hard to take, particularly from a relative, a
friend, an acquaintance, or a stranger."
-- Franklin P. Jones
Roel Schroeven
More information about the Python-list
mailing list