Setup dictionary lazily Setup dictionary lazily python python

Setup dictionary lazily


Don't inherit build-in dict. Even if you overwrite dict.__getitem__() method, dict.get() would not work as you expected.

The right way is to inherit abc.Mapping from collections.

from collections.abc import Mappingclass LazyDict(Mapping):    def __init__(self, *args, **kw):        self._raw_dict = dict(*args, **kw)    def __getitem__(self, key):        func, arg = self._raw_dict.__getitem__(key)        return func(arg)    def __iter__(self):        return iter(self._raw_dict)    def __len__(self):        return len(self._raw_dict)

Then you can do:

settings = LazyDict({    'expensive1': (expensive_to_compute, 1),    'expensive2': (expensive_to_compute, 2),})

I also list sample code and examples here: https://gist.github.com/gyli/9b50bb8537069b4e154fec41a4b5995a


If you don't separe the arguments from the callable, I don't think it's possible. However, this should work:

class MySettingsDict(dict):    def __getitem__(self, item):        function, arg = dict.__getitem__(self, item)        return function(arg)def expensive_to_compute(arg):    return arg * 3

And now:

>>> settings = MySettingsDict({'expensive1': (expensive_to_compute, 1),'expensive2': (expensive_to_compute, 2),})>>> settings['expensive1']3>>> settings['expensive2']6

Edit:

You may also want to cache the results of expensive_to_compute, if they are to be accessed multiple times. Something like this

class MySettingsDict(dict):    def __getitem__(self, item):        value = dict.__getitem__(self, item)        if not isinstance(value, int):            function, arg = value            value = function(arg)            dict.__setitem__(self, item, value)        return value

And now:

>>> settings.values()dict_values([(<function expensive_to_compute at 0x9b0a62c>, 2),(<function expensive_to_compute at 0x9b0a62c>, 1)])>>> settings['expensive1']3>>> settings.values()dict_values([(<function expensive_to_compute at 0x9b0a62c>, 2), 3])

You may also want to override other dict methods depending of how you want to use the dict.


Store references to the functions as the values for the keys i.e:

def A():    return "that took ages"def B():    return "that took for-ever"settings = {    "A": A,    "B": B,}print(settings["A"]())

This way, you only evaluate the function associated with a key when you access it and invoke it. A suitable class which can handle having non-lazy values would be:

import typesclass LazyDict(dict):    def __getitem__(self,key):        item = dict.__getitem__(self,key)        if isinstance(item,types.FunctionType):            return item()        else:            return item

usage:

settings = LazyDict([("A",A),("B",B)])print(settings["A"])>>> that took ages