How to implement a lazy setdefault?
This can be accomplished with defaultdict
, too. It is instantiated with a callable which is then called when a nonexisting element is accessed.
from collections import defaultdictd = defaultdict(noisy_default)d[1] # noised[1] # no noise
The caveat with defaultdict
is that the callable gets no arguments, so you can not derive the default value from the key as you could with dict.setdefault
. This can be mitigated by overriding __missing__
in a subclass:
from collections import defaultdictclass defaultdict2(defaultdict): def __missing__(self, key): value = self.default_factory(key) self[key] = value return valuedef noisy_default_with_key(key): print key return key + 1d = defaultdict2(noisy_default_with_key)d[1] # prints 1, sets 2, returns 2d[1] # does not print anything, does not set anything, returns 2
For more information, see the collections module.
You can do that in a one-liner using a ternary operator:
value = cache[key] if key in cache else cache.setdefault(key, func(key))
If you are sure that the cache
will never store falsy values, you can simplify it a little bit:
value = cache.get(key) or cache.setdefault(key, func(key))
No, evaluation of arguments happens before the call. You can implement a setdefault
-like function that takes a callable as its second argument and calls it only if it is needed.