Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy evaluation of dict values?

Suppose I have the following dict d={'a': heavy_expression1, 'b': heavy_expression2}.

How can I wrap the expressions, so that they are evaluated once they are accessed and after this no evaluation is performed?

d['a'] # only here heavy_expression1 is executed
d['a'] # no execution here, already calculated

Do I need to use lambda or generators?

like image 909
Andrew Fount Avatar asked Sep 14 '25 22:09

Andrew Fount


2 Answers

A version with lambdas:

class LazyDict(dict):
    def __init__(self, lazies):
        self.lazies = lazies
    def __missing__(self, key):
        value = self[key] = self.lazies[key]()
        return value

d = LazyDict({'a': lambda: print('heavy_expression1') or 1,
              'b': lambda: print('heavy_expression2') or 2})
print(d['a'])
print(d['a'])
print(d['b'])
print(d['b'])

Output:

heavy_expression1
1
1
heavy_expression2
2
2
like image 95
no comment Avatar answered Sep 16 '25 12:09

no comment


Another approach would be interrupting the __getitem__ method in subclass and do the caching there:

class LazyDict(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.cache = {}

    def __getitem__(self, item):
        if item in self.cache:
            return self.cache[item]
        result = super().__getitem__(item)()

        self.cache[item] = result
        return result

Here is the test case with functions: (lambda perfectly fits here if you don't want to define functions)

def heavy_expresion1():
    print('heavy expression1 is calculated')
    return 10

def heavy_expresion2():
    print('heavy expression2 is calculated')
    return 20

d = LazyDict({'a': heavy_expresion1, 'b': heavy_expresion2})
print(d)

print(d['a'])
print(d['a'])

print(d['b'])
print(d['b'])

output :

{'a': <function heavy_expresion1 at 0x000001AFE783ED30>, 'b': <function heavy_expresion2 at 0x000001AFE8036940>}
heavy expression1 is calculated
10
10
heavy expression2 is calculated
20
20
like image 43
SorousH Bakhtiary Avatar answered Sep 16 '25 10:09

SorousH Bakhtiary