lonelyenvoy / python-memoization

A powerful caching library for Python, with TTL support and multiple algorithm options.
MIT License
230 stars 15 forks source link

Memoization of classes does not work #12

Closed dzimmanck closed 3 years ago

dzimmanck commented 4 years ago

I am attempting to memoize a class that has an expensive calculation in the init. If the class has a str method, decorating the class with a @cached() does not throw an error, but also does not seem to function (i.e. No memoization observed). If you use a custom key maker, you get an TypeError saying the key maker signature does not match the function arguments (Think that is a clue right there).

Memoizing classes is not that uncommon of a feature so I think this should be supported. Here is a simple version if the problem below for reproducing.

from memoization import cached
import time
import timeit

class Point():
    def __init__(self, x, y):
        self.x = x
        self.y = y

        # some super intense computation here
        time.sleep(5)

# custom key-maker for the class
def key_maker(point):
    key = hash((point.x, point.y))
    return key

@cached(custom_key_maker=key_maker)
class CachedPoint(Point):
    def __init__(self, x, y):
        super().__init__(x, y)

if __name__ == "__main__":

    t0 = timeit.default_timer()
    p = Point(1, 2)
    t1 = timeit.default_timer()
    print(f'Making a point took {t1-t0} seconds')

t0 = timeit.default_timer()
p = Point(1, 2)
t1 = timeit.default_timer()
print(f'Re-making a point took {t1-t0} seconds')
lonelyenvoy commented 3 years ago

You are not using @cached correctly.

So, the following code works:

from memoization import cached
import time
import timeit

class Point():
    def __init__(self, x, y):
        self.x = x
        self.y = y

        # some super intense computation here
        time.sleep(5)

@cached
class CachedPoint(Point):
    def __init__(self, x, y):
        super().__init__(x, y)

if __name__ == "__main__":
    t0 = timeit.default_timer()
    p = CachedPoint(1, 2)
    t1 = timeit.default_timer()
    print(f'Making a point took {t1-t0} seconds')

    t0 = timeit.default_timer()
    p = CachedPoint(1, 2)
    t1 = timeit.default_timer()
    print(f'Re-making a point took {t1-t0} seconds')

Output:

Making a point took 5.0022731049999996 seconds
Re-making a point took 1.9499999999617046e-05 seconds
lonelyenvoy commented 3 years ago

If you have further questions, please leave a comment and reopen this issue. Thanks!