Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use Python's functools @cache based on identity?

I would like to have a Python @cache decorator based on identity, not __hash__/__equal.

That is to say, I would like the cached value for an argument ka NOT to be used for a different object ka2, even if ka == ka2.

Is there a way to do that?

In code:

from functools import cache


class Key:
    def __init__(self, value):
        self.value = value

    def __eq__(self, another):
        print(f"__eq__ {self.value}, {another.value}")
        return another.value == self.value

    def __hash__(self):
        print(f"__hash__ {self.value}")
        return hash(self.value)

    def __repr__(self):
        return self.value


i = 0


@cache
def foo(key):
    global i
    i += 1
    print(f"Computing foo({key}) = {i}")
    return i


ka = Key('a')
ka2 = Key('a')

print(f"foo(ka): {foo(ka)}")
print(f"foo(ka2): {foo(ka2)}")  # I would like the cached value for ka NOT to be used even though ka2 == ka.
like image 448
user118967 Avatar asked Oct 14 '25 15:10

user118967


1 Answers

Make a wrapper like Key that compares by the identity of its wrapped object, and wrap your caching function in a helper that uses the wrapper:

class Id:
  __slots__="x",
  def __init__(self,x): self.x=x
  def __hash__(self): return id(self.x)
  def __eq__(self,o): return self.x is o.x

def cache_id(f):
  @functools.cache
  def id_f(i): return f(i.x)
  @functools.wraps(f)
  def call(x): return id_f(Id(x))
  return call

@cache_id
def foo(key): …
like image 85
Davis Herring Avatar answered Oct 17 '25 05:10

Davis Herring



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!