cache_decorator icon indicating copy to clipboard operation
cache_decorator copied to clipboard

Handle in a better way decoration of class methods.

Open LucaCappelletti94 opened this issue 3 years ago • 4 comments

LucaCappelletti94 avatar Mar 03 '21 13:03 LucaCappelletti94

I tried your method to cache some computation for a class but I does not seem to work for methods of an object:

from cache_decorator import Cache

class Foo():
    def __init__(self, bar):
        self.bar = bar
    
    @Cache()
    def my_bar(self):
        return self.bar

for i in [1, 2]:
    foo = Foo(i)
    print('I expect',i,'and print', foo.my_bar())

which prints

I expect 1 and print 1
I expect 2 and print 1

This seems to be fixable by adding something in the prefix.

ngast avatar Apr 13 '21 07:04 ngast

Hello @ngast, as you have surely noticed this is a known issue that we are trying to understand how to solve best. The issue is that one solution may take the form of hashing the entire class (the self object) and that may include in some cases classes that are not hashable. Another solution may take the form of specifying which parameters of the class one may want to hash.

And yet another option is that users may be interested in altogether ignore the self method. Another issue may be the interaction of the cached method with a possible child class. How should it behave in that case?

Could you share your opinion on this issue? We have been struggling for a while now about how to proceed to fix this.

LucaCappelletti94 avatar Apr 13 '21 13:04 LucaCappelletti94

I am not sure if this would be the best option but the way I intended to do (before looking for an already existing solution) would have been to create a method for my class like "hash_of_instance(self)" that I would correspond to a hash of the interesting parameters. Then, I would concatenate this hash to the filename of the cache.

ngast avatar Apr 13 '21 13:04 ngast

Hi, sorry for the long wait, we finally figured out how to properly handle methods. From the new 2.1.0 version, you can either use in the path the instance attributes like:


class A:
    """Test that we can hash methods if self implements Hashable"""
    def __init__(self, x):
        self.x = x
    
    @Cache(
        cache_path="{cache_dir}/{a.name}_{self.x}.pkl",
        cache_dir="./test_cache",
        backup=False,
    )
    def cached_function(self, a):
        sleep(2)
        return [1, 2, 3]

Or you can implement your custom hash:


from dict_hash import Hashable

class B(Hashable):
    """Test that we can hash methods if self implements Hashable"""
    def __init__(self, x):
        self.x = x
    
    @Cache(
        cache_path="{cache_dir}/{a}_{_hash}.pkl",
        cache_dir="./test_cache",
        backup=False,
    )
    def cached_function(self, a):
        sleep(2)
        return [1, 2, 3]

    def consistent_hash(self) -> str:
        return str(self.x)

I hope this will solve this problem!

zommiommy avatar May 24 '22 16:05 zommiommy