You are supposed to be able to override how pickle pickles an object with __getstate__ and __setstate__. However, these methods are ignored in a dataclass when specifying both frozen=True and slots=True.
See this example:
import pickle
from dataclasses import dataclass
@dataclass(frozen=True, slots=True)
class Foo:
bar: int
def __getstate__(self):
print("getstate")
return {"bar": self.bar}
def __setstate__(self, state):
print("setstate")
object.__setattr__(self, "bar", state["bar"])
b = pickle.dumps(Foo(1))
foo = pickle.loads(b)
The expected "getstate" and "setstate" lines are never printed because the supplied methods are never called. If either frozen or slots is removed, the expected lines are printed.
From the source code, it is pretty clear why this is happening. If frozen and slots are both True, then special versions of __getstate__ and __setstate__ are unconditionally attached to the dataclass. The dataclass decorator should probably treat this way that it does other methods—only add a method if it is not already present.
Linked PRs
You are supposed to be able to override how
picklepickles an object with__getstate__and__setstate__. However, these methods are ignored in a dataclass when specifying bothfrozen=Trueandslots=True.See this example:
The expected "getstate" and "setstate" lines are never printed because the supplied methods are never called. If either
frozenorslotsis removed, the expected lines are printed.From the source code, it is pretty clear why this is happening. If
frozenandslotsare bothTrue, then special versions of__getstate__and__setstate__are unconditionally attached to the dataclass. The dataclass decorator should probably treat this way that it does other methods—only add a method if it is not already present.Linked PRs
__{get,set}state__in slotted frozen dataclasses #104041__{get,set}state__in slotted frozen dataclasses (GH-104041) #104044