If a base class is a PyVarObject, classes inheriting from that base cannot add __dict__ or __weakref__ through __slots__ declaration on the class. If __slots__ is not empty, the following exception is raised:
TypeError: nonempty __slots__ not supported for subtype of '...'
Assume that we have a PyVarObject foo.FooBase class (implementation below). Trying to inherit from the class and requesting weakref support doesn't work.
This is a duplicate of #61497. The isn't isn't so much that these particular slots aren't supported, but that no slots are supported at all var these objects.
changed the title [-]Cannot use __slots__ = ('__weakref__', '__dict__') with PyVarObject[/-][+]Allow __slots__ on classes with Py_TPFLAGS_ITEMS_AT_END[/+]on Apr 24, 2023
This particular issue (support __dict__ and __weakref__) can be solved relatively easy. Currently variable length types can have either both __dict__ and __weakref__, or none of them, so it is possible.
But I think that we should support also general slots, there are use cases for this. So this issue can be a part of #41779.
The only Py_TPFLAGS_ITEMS_AT_END type in stdlib is type itself.
So, this PR allows slotted types. Adding data descriptors to types leads to some rather hard-to-explain behaviour, for example:
I do not understand what problems can be caused by adding support of __slots__ in the type subtypes.
There are already data descriptors in type. And they can be different from data descriptors in __dict__. This is a feature. For example, functions have __doc__, and it is different from the __doc__ of the function type.
PEP 697 intentionally added support of data descriptors referring to the extended data in the type subtypes. If this was mistake, should not we forbid Py_TPFLAGS_ITEMS_AT_END for the type subtypes?
There are already data descriptors in type. And they can be different from data descriptors in __dict__. This is a feature. For example, functions have __doc__, and it is different from the __doc__ of the function type.
Yes, that is a feature, but I doubt that users expect __slots__ to behave this way.
IMO, the usual visible effect of __slots__ is to:
disable some attributes (not applicable here since type already has __dict__)
improve memory use (not too important here: we don't avoid a __dict__, and type itself is huge: you'd need many slots for them to be a significant part of a type's memory footprint.)
Descriptors are an implementation detail; and here they'd be responsible for confusing interactions with optimizations that assume attributes are in __dict__.
I can't see a use case for __slots__ on type, only downsides.
It's very different with third-party types that define Py_TPFLAGS_ITEMS_AT_END though. On something that doesn't have __dict__, or doesn't assume that data is in __dict__, __slots__ can be very useful. It's only type where they seem like a footgun.
PEP 697 intentionally added support of data descriptors referring to the extended data in the type subtypes.
PEP 697 was primarily about adding a C-level chunk of memory, not about Python attributes. It's true that PEP 697 also added a way to expose the contents of that memory to Python, but that wasn't the main point -- and it definitely was not specifically for type.
Defining attributes is very different in C than in Python.
Allowing __slots__ in classes with the Py_TPFLAGS_ITEMS_AT_END flag will not add anything principally new. It will just enable in Python what is already allowed in C (but in more limited form). It will just remove unnecessary restriction. If there is any issue with this for type subclasses, we should disallow creating such descriptors in C. But I do not think there will be any new issue, because standard data descriptors existed in type for years.
doesn't assume that data is in __dict__
This assumption never was correct.
>>> deff(): 'docstring'
...
>>> f.__doc__
'docstring'
>>> '__doc__'in f.__dict__
False
>>> type(f).__doc__
'Create a function object.\n\n code\n a code object\n globals\n the globals dictionary\n name\n a string that overrides the name from the code object\n argdefs\n a tuple that specifies the default argument values\n closure\n a tuple that supplies the bindings for free variables\n kwdefaults\n a dictionary that specifies the default keyword argument values'
I only want consistency. Either allow __slots__ in types with Py_TPFLAGS_ITEMS_AT_END, or disallow data descriptors referring to the data added in subclasses with Py_TPFLAGS_ITEMS_AT_END. Either allow __slots__ in types with Py_TPFLAGS_ITEMS_AT_END except the type subclasses, or disallow descriptors for the new data in the type subclasses.
Right, in general it wasn't.
I don't think __doc__ is a good example -- it has its own specialized descriptor to ensure it's not inherited. It doesn't work like normal attributes.
Allowing descriptors on type make it possible to add functionality like that. That's good; I wouldn't disallow them entirely.
But with __slots__, the way they're defined automatically from Python code makes them confusing. Combined with the fact that I can see no good use case for __slots__ on type, I'm reluctant to add this new feature. (You can already add Python attributes to classes -- it's different from exposing C data by PEP 697.)
I think the discussion is going in circles. Do you want to open a Discourse topic to get additional opinions?
Activity
ronaldoussoren commented on Apr 24, 2023
This is a duplicate of #61497. The isn't isn't so much that these particular slots aren't supported, but that no slots are supported at all var these objects.
encukou commented on Apr 24, 2023
Let's use this issue for enabling this with Py_TPFLAGS_ITEMS_AT_END specifically. I plan to look into it for 3.13.
serhiy-storchaka commented on Dec 30, 2024
This particular issue (support __dict__ and __weakref__) can be solved relatively easy. Currently variable length types can have either both __dict__ and __weakref__, or none of them, so it is possible.
But I think that we should support also general slots, there are use cases for this. So this issue can be a part of #41779.
pythongh-103740: Improve support of __slots__ for variable-length cla…
serhiy-storchaka commented on Nov 16, 2025
#141636 implements two features:
If you with, I can split it on two PRs, if this will not slow down review.
My next step is to support any __slots__ for subclasses of tuple. And then we can plan support any variable-length types (it is not easy).
pythongh-103740: Improve support of __slots__ for variable-length cla…
pythongh-103740: Allow defining the __dict__ and __weakref__ __slots_…
pythongh-103740: Support any slots in the type subclasses
pythongh-103740: Support any slots in the type subclasses
encukou commented on Nov 20, 2025
Copying from the PR:
The only Py_TPFLAGS_ITEMS_AT_END type in stdlib is type itself.
So, this PR allows slotted types. Adding data descriptors to types leads to some rather hard-to-explain behaviour, for example:
Do we want to make this easier?
encukou commented on Nov 20, 2025
Py_TPFLAGS_ITEMS_AT_END, this feature looks to be specifically about allowing descriptors for type, so I'm not sure we want it.
What about explicitly disabling arbitrary __slots__ on type subclasses, given how many type optimizations assume that the __dict__ is authoritative?
serhiy-storchaka commented on Nov 20, 2025
I do not understand what problems can be caused by adding support of __slots__ in the type subtypes.
encukou commented on Nov 21, 2025
Yes, that is a feature, but I doubt that users expect __slots__ to behave this way.
IMO, the usual visible effect of __slots__ is to:
Descriptors are an implementation detail; and here they'd be responsible for confusing interactions with optimizations that assume attributes are in __dict__.
I can't see a use case for __slots__ on type, only downsides.
It's very different with third-party types that define Py_TPFLAGS_ITEMS_AT_END though. On something that doesn't have __dict__, or doesn't assume that data is in __dict__, __slots__ can be very useful. It's only type where they seem like a footgun.
PEP 697 was primarily about adding a C-level chunk of memory, not about Python attributes. It's true that PEP 697 also added a way to expose the contents of that memory to Python, but that wasn't the main point -- and it definitely was not specifically for type.
Defining attributes is very different in C than in Python.
serhiy-storchaka commented on Nov 21, 2025
Allowing __slots__ in classes with the Py_TPFLAGS_ITEMS_AT_END flag will not add anything principally new. It will just enable in Python what is already allowed in C (but in more limited form). It will just remove unnecessary restriction. If there is any issue with this for type subclasses, we should disallow creating such descriptors in C. But I do not think there will be any new issue, because standard data descriptors existed in type for years.
This assumption never was correct.
I only want consistency. Either allow __slots__ in types with Py_TPFLAGS_ITEMS_AT_END, or disallow data descriptors referring to the data added in subclasses with Py_TPFLAGS_ITEMS_AT_END. Either allow __slots__ in types with Py_TPFLAGS_ITEMS_AT_END except the type subclasses, or disallow descriptors for the new data in the type subclasses.
encukou commented on Nov 24, 2025
Right, in general it wasn't.
I don't think __doc__ is a good example -- it has its own specialized descriptor to ensure it's not inherited. It doesn't work like normal attributes.
Allowing descriptors on type make it possible to add functionality like that. That's good; I wouldn't disallow them entirely.
But with __slots__, the way they're defined automatically from Python code makes them confusing. Combined with the fact that I can see no good use case for __slots__ on type, I'm reluctant to add this new feature. (You can already add Python attributes to classes -- it's different from exposing C data by PEP 697.)
I think the discussion is going in circles. Do you want to open a Discourse topic to get additional opinions?