Say a I have a dataclass in python3. I want to be able to hash and order these objects. I do not want these to be immutable.
I only want them ordered/hashed on id.
I see in the docs that I can just implement _hash_ and all that but I'd like to get datacalsses to do the work for me because they are intended to handle this.
from dataclasses import dataclass, field @dataclass(eq=True, order=True) class Category: id: str = field(compare=True) name: str = field(default="set this in post_init", compare=False) a = sorted(list(set([ Category(id='x'), Category(id='y')]))) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'Category'
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.
It is not possible to create truly immutable Python objects. However, by passing frozen=True to the dataclass() decorator you can emulate immutability.
With @dataclass(frozen=True) then assigning to fields after the object has been instantiated will raise a FrozenInstanceError . This emulates read-only frozen instances, and gives the advantages of immutability.
All immutable built-in objects in Python are hashable like tuples while the mutable containers like lists and dictionaries are not hashable. Objects which are instances of the user-defined class are hashable by default, they all compare unequal, and their hash value is their id().
From the docs:
Here are the rules governing implicit creation of a
__hash__()
method:[...]
If
eq
andfrozen
are both true, by defaultdataclass()
will generate a__hash__()
method for you. Ifeq
is true andfrozen
is false,__hash__()
will be set toNone
, marking it unhashable (which it is, since it is mutable). Ifeq
is false,__hash__()
will be left untouched meaning the__hash__()
method of the superclass will be used (if the superclass is object, this means it will fall back to id-based hashing).
Since you set eq=True
and left frozen
at the default (False
), your dataclass is unhashable.
You have 3 options:
frozen=True
(in addition to eq=True
), which will make your class immutable and hashable.Set unsafe_hash=True
, which will create a __hash__
method but leave your class mutable, thus risking problems if an instance of your class is modified while stored in a dict or set:
cat = Category('foo', 'bar') categories = {cat} cat.id = 'baz' print(cat in categories) # False
__hash__
method.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