How to lru_cache a function when arguments are object instances and the cache needs to look into instance attributes?
Asked Answered
E

1

6

I am trying to implement the lru_cache on a function that takes in a python object as an argument. The function should return a cached value only if it's argument's attributes have not changed. However, it looks like the lru_cache only does a "shallow look" into the functions arguments to see what has changed and ignores any attribute changes.

For e.g. in the below the calculate function which is decorated with lru_cache takes in a cell instance and returns a calculation based on the instance's attributes.

from functools import lru_cache

class Cell:

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


@lru_cache()
def calculate(cell):
    return cell.x + cell.y

When running this:

if __name__ == '__main__':

    cellA = Cell(1,2)
    print(calculate(cellA))
    #returns 3 correctly

    #let's change cellA's attribute of x to something else
    cellA.x = 10

    print(calculate(cellA))
    #also returns 3, but should return 12!

I'd like the second call to function to actually not used the cached value as the attribute x has now been changed.

A very inelegant workaround is to pass in "fake arguments" to the calculate function as such:

@lru_cache()
def calculate(cell, prec):
    return cell.x + cell.y

if __name__ == '__main__':

    cellA = Cell(1,2)
    print(calculate(cellA, prec=cellA.x))
    #returns 3

    #let's change cellA's attribute of x to something else
    cellA.x = 10


    print(calculate(cellA, prec=cellA.x))
    #now returns 12!

The above works but seems like a bad way to go about doing this.

Eliathan answered 12/5, 2020 at 20:1 Comment(0)
M
0

The documentation states that the arguments must be hashable. Therefore, implement a __hash__ method and make it comparable (__eq__/__cmp__).

Massachusetts answered 14/10 at 5:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.