that matt bone .com |

delaying computation: lazy dictionaries in Python

Yesterday I had a problem I ended up solving another way, but my first approach required a lazy dictionary. That is, a dictionary filled with the results of some other function, but also one that only evaluated this computation when the dictionary was first accessed. Here’s a silly example use case:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    class LazyDictionary(object):
    
        def __init__(self, callback=dict):
            self.data = None
            self.callback = callback
    
        def evaluate_callback(self):
            self.data = self.callback()
    
        def __getitem__(self, name):
            if(self.data is None):
                self.evaluate_callback()
            return self.data.__getitem__(name)
    
        def __setitem__(self, name, value):
            if(self.data is None):
                self.evaluate_callback()
            return self.data.__setitem__(name, value)
    
        def __getattr__(self, name):
            if(self.data is None):
                self.evaluate_callback()
            return getattr(self.data, name)

The real version I started to use (and then threw out because it was not needed) inherited from a dict instead of using delegation. At the time I thought this was necessary to get it to play nice with the Django templating system (I may have been wrong about this). Anyways, I like this version much better, and I view inheritance for the composition of behavior with growing skepticism each day.