Justin Furuness <jfurun...@gmail.com> added the comment:
Thank you for the in-depth explanation. That all makes sense to me, I have run into the __slots__ with defaults issues before, I'll be sure to try out these fixes. I appreciate you taking the time. Thanks, Justin On Tue, Oct 19, 2021 at 5:28 PM Josh Rosenberg <rep...@bugs.python.org> wrote: > > Josh Rosenberg <shadowranger+pyt...@gmail.com> added the comment: > > You're right that in non-dataclass scenarios, you'd just use __slots__. > > The slots=True thing was necessary for any case where any of the > dataclass's attributes have default values (my_int: int = 0), or are > defined with fields (my_list: list = field(default_factory=list)). The > problem is that __slots__ is implemented by, after the class definition > ends, creating descriptors on the class to access the data stored at known > offsets in the underlying PyObject structure. Those descriptors themselves > being class attributes means that when the type definition machinery tries > to use __slots__ to create them, it finds conflicting class attributes (the > defaults/fields) that already exist and explodes. > > Adding support for slots=True means it does two things: > > 1. It completely defines the class without slots, extracts the stuff it > needs to make the dataclass separately, then deletes it from the class > definition namespace and makes a *new* class with __slots__ defined (so no > conflict occurs) > 2. It checks if the dataclass is also frozen, and applies alternate > __getstate__/__setstate__ methods that are compatible with a frozen, > slotted dataclass > > #2 is what fixes this bug (while #1 makes it possible to use the full > range of dataclass features without sacrificing the ability to use > __slots__). If you need this to work in 3.9, you could borrow the 3.10 > implementations that make this work for frozen dataclasses to explicitly > define __getstate__/__setstate__ for your frozen slotted dataclasses: > > def __getstate__(self): > return [getattr(self, f.name) for f in fields(self)] > > > def __setstate__(self, state): > for field, value in zip(fields(self), state): > # use setattr because dataclass may be frozen > object.__setattr__(self, field.name, value) > > I'm not closing this since backporting just the fix for frozen slotted > dataclasses (without backporting the full slots=True functionality that's a > new feature) is possibly within scope for a bugfix release of 3.9 (it > wouldn't change the behavior of working code, and fixes broken code that > might reasonably be expected to work). > > ---------- > > _______________________________________ > Python tracker <rep...@bugs.python.org> > <https://bugs.python.org/issue45520> > _______________________________________ > ---------- _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue45520> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com