On Mon, Dec 21, 2020 at 12:47 AM <2qdxy4rzwzuui...@potatochowder.com> wrote: > > On 2020-12-19 at 22:29:34 +0100, > Roel Schroeven <r...@roelschroeven.net> wrote: > > > 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) > > There's no need to pass all those arguments through dict_get_lazily, and > the language already has a way to evaluate an expression lazily: > > def dict_get_lazily(d, key, f): > try: > return d[key] > except KeyError: > return f() > > some_var = dict_get_lazily(d, 'spam', lambda: some_function(31, 11)) >
class LazyDict(dict): def __missing__(self, key): # Pretend this is slow print("slow function called") return 31 + 11 d = LazyDict({ 'spam': 0, 'ham': 1, 'parrot': 2, }) print(d['spam']) print(d['eggs']) Guaranteed to be called when and only when the key is missing. This does imply a variant architecture in which the data structure itself is aware of the calculations necessary to generate the data, so it may not be appropriate to all situations, but it's clean, easy, and efficient. If you can't do this, I'd recommend using the try/except method, maybe wrapped up in a function if you want to. In the case where the key is found, the cost is one try block and one lookup - barely more than any other option (for the record, a try block is pretty cheap in CPython, and it's only costly when you hit an exception); and where it isn't found, it's two lookups plus the cost of generating the default (and we've already established that generating the default is expensive, otherwise setdefault would be appropriate). ChrisA -- https://mail.python.org/mailman/listinfo/python-list