How to combine dataclass, property, and lru_cache

Question:

I’m trying to combine dataclasses, properties and lru_caches for some computational science code:

from dataclasses import dataclass
from typing import Any
from functools import lru_cache
@dataclass
class F:
    a: Any = 1
    b: Any = 2
    c: Any = 3
    @property
    @lru_cache(1)
    def d(self):
        print('Computing d')
        return (self.a+self.b)**self.c
f=F()
print(f.d)
print(f.d)

I hoped to see

Computing d
27
27

but get

TypeError: unhashable type: 'F'

Is there a way to fix this?

Asked By: Bananach

||

Answers:

lru_cache is like memoization so it hashes arguments passed to the function and stores the result. Your class isn’t hashable. To make it hashable, add something like this

class F:
    ....
    def __hash__(self):
        return hash((self.a, self.b, self.c))

The reason for this is that these 3 attributes make each instance ‘unique’ – we don’t need to hash the methods as all instances have the same methods.

On most normal classes, its __dict__ is used for general hashing unless a __hash__ method is found. The dataclass documentation explains that it is possible for the dataclass to generate a hashing method but it depends on how you set up the dataclass as by default the object is assumed to be mutable (and mutable objects like lists can’t be hashed).

The dataclass documentation states that a hash method will be generated if the parameters eq and frozen are set to True when decorating with @dataclass(), but your application may not warrant this as frozen prohibits attribute assignment on instances.

https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass

Answered By: N Chauhan