The following will work, but I'd rather not need to repeat the __hash__ in each subclass.  Is there a way to tell the dataclass to inherit the hash function (i.e. not set it to None)?
from dataclasses import dataclass
@dataclass
class Hashable:
    def __hash__(self):
        hashed = hash((
            getattr(self, key)
            for key in self.__annotations__
            ))
        return hashed
@dataclass
class Node(Hashable):
    name: str = 'Undefined'
    def __hash__(self):
        return Hashable.__hash__(self)
                Both SuperClass and SubClass are DataClasses – although super-class or sub-class being a normal class is also possible. When a DataClass inherits a normal class, the __init__() from the super-class is overridden in sub-class.
Python hash() function is a built-in function and returns the hash value of an object if it has one. The hash value is an integer which is used to quickly compare dictionary keys while looking at a dictionary.
Since you set eq=True and left frozen at the default ( False ), your dataclass is unhashable. You have 3 options: Set frozen=True (in addition to eq=True ), which will make your class immutable and hashable.
The reason your __hash__ is being set to None is that dataclasses is trying to stop you from shooting yourself in the foot. Your second class has eq=True for the dataclass decorator (this is the default value). From the docs:
Here are the rules governing implicit creation of a
__hash__()method. Note that you cannot both have an explicit__hash__()method in your dataclass and set unsafe_hash=True; this will result in aTypeError.If eq and frozen are both true, by default dataclass() will generate a
__hash__()method for you. If eq is true and frozen is false, __hash__() will be set to None, marking it unhashable (which it is, since it is mutable). If eq is false,__hash__()will be left untouched meaning the__hash__()method of the superclass will be used (if the superclass isobject, this means it will fall back to id-based hashing).
So just pass eq=False:
In [1]: from dataclasses import dataclass
   ...:
   ...:
   ...: @dataclass
   ...: class Hashable:
   ...:
   ...:     def __hash__(self):
   ...:         hashed = hash((
   ...:             getattr(self, key)
   ...:             for key in self.__annotations__
   ...:             ))
   ...:         return hashed
   ...:
   ...:
   ...: @dataclass(eq=False)
   ...: class Node(Hashable):
   ...:     name: str = 'Undefined'
   ...:
In [2]: hash(Node())
Out[2]: -9223372036579626267
However, as pointed out in the comments, this isn't very safe, since you have a mutable object that is now hash-able, and inconsistently so with it's implementation of __eq__, which it is inheriting from Hashable
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With