Repository navigation
Allow __slots__ on classes with Py_TPFLAGS_ITEMS_AT_END #103740
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
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.
Let's use this issue for enabling this with
Py_TPFLAGS_ITEMS_AT_ENDspecifically. I plan to look into it for 3.13.- changed the title
[-]Cannot use __slots__ = ('__weakref__', '__dict__') with PyVarObject[/-][+]Allow __slots__ on classes with Py_TPFLAGS_ITEMS_AT_END[/+]on Apr 24, 2023 - addedinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
on Nov 30, 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.
#141636 implements two features:
- Support
__dict__and__weakref__slots for any class. - Support any
__slots__for subclasses oftypeand classes with Py_TPFLAGS_ITEMS_AT_END.
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 oftuple. And then we can plan support any variable-length types (it is not easy).- Support
- addedtype-featureA feature request or enhancementA feature request or enhancement3.15bugs and security fixesbugs and security fixesand removedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Nov 16, 2025 - added 4 commits that reference this issue
on Nov 16, 2025 Copying from the PR:
The only
Py_TPFLAGS_ITEMS_AT_ENDtype in stdlib istypeitself.
So, this PR allows slotted types. Adding data descriptors to types leads to some rather hard-to-explain behaviour, for example:>>> class Meta(type): ... __slots__ = ['foo'] # now possible ... >>> class X(metaclass=Meta): ... def foo(self): return 'f' ... >>> X().foo <bound method X.foo of <__main__.X object at 0x7f7c579c2900>> >>> X.foo Traceback (most recent call last): File "<python-input-3>", line 1, in <module> X.foo AttributeError: 'Meta' object has no attribute 'foo' >>> X.foo = slice >>> X.foo(X()) slice(None, <__main__.X object at 0x7f7c5788c050>, None) >>> X().foo() 'f'
Do we want to make this easier?
Py_TPFLAGS_ITEMS_AT_END, this feature looks to be specifically about allowing descriptors fortype, so I'm not sure we want it.What about explicitly disabling arbitrary
__slots__ontypesubclasses, given how manytypeoptimizations assume that the__dict__is authoritative?I do not understand what problems can be caused by adding support of
__slots__in thetypesubtypes.- 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
typesubtypes. If this was mistake, should not we forbidPy_TPFLAGS_ITEMS_AT_ENDfor thetypesubtypes?
- There are already data descriptors in
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
typealready has__dict__) - improve memory use (not too important here: we don't avoid a
__dict__, andtypeitself 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__ontype, only downsides.It's very different with third-party types that define
Py_TPFLAGS_ITEMS_AT_ENDthough. On something that doesn't have__dict__, or doesn't assume that data is in__dict__,__slots__can be very useful. It's onlytypewhere they seem like a footgun.PEP 697 intentionally added support of data descriptors referring to the extended data in the
typesubtypes.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.- disable some attributes (not applicable here since
Allowing
__slots__in classes with thePy_TPFLAGS_ITEMS_AT_ENDflag 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 fortypesubclasses, we should disallow creating such descriptors in C. But I do not think there will be any new issue, because standard data descriptors existed intypefor years.doesn't assume that data is in
__dict__This assumption never was correct.
>>> def f(): '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 withPy_TPFLAGS_ITEMS_AT_END, or disallow data descriptors referring to the data added in subclasses withPy_TPFLAGS_ITEMS_AT_END. Either allow__slots__in types withPy_TPFLAGS_ITEMS_AT_ENDexcept thetypesubclasses, or disallow descriptors for the new data in thetypesubclasses.This assumption never was correct.
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 ontypemake 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__ontype, 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?
Bug report
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
PyVarObjectfoo.FooBaseclass (implementation below). Trying to inherit from the class and requesting weakref support doesn't work.`foo` module implementation
Your environment
CC: @encukou
Linked PRs