I've got conflicts between Python's typing system and __slots__
. Here is a small reproducible example.
from typing import TypeVar, Generic, Sequence
T = TypeVar("T")
class TestGeneric(Sequence, Generic[T]):
__slots__ = ("test",)
def __init__(self, test: T):
self.test = [test]
def __iter__(self):
return iter(self.test)
def __len__(self):
return len(self.test)
def __contains__(self, item):
return item in self.test
def __getitem__(self, _):
return self.test[0]
Now whenever I try to specify a content type, e.g.
V = TestGeneric[int]
I get
ValueError: 'test' in __slots__ conflicts with class variable
I use Generics
in classes without slots a lot, hence I think this error has to be linked to __slots__
. Moreover, the same class works fine, if you remove the __slots__
Fixed attributes One of the reasons to use __dict__ is its flexibility after creating the object where you can add new attributes. However, __slots__ will fix the attributes when you create the class. So, it's not possible to add new attributes later.
"You would want to use __slots__ if you are going to instantiate a lot (hundreds, thousands) of objects of the same class." Abstract Base Classes, for example, from the collections module, are not instantiated, yet __slots__ are declared for them.
Slots in Python is a special mechanism that is used to reduce memory of the objects. In Python, all the objects use a dynamic dictionary for adding an attribute. Slots is a static type method in this no dynamic dictionary are required for allocating attribute.
I would say that this is a bug in the typing
module, which does not properly take into account __slots__
when creating new types.
This problem can be reproduced with this very short example:
>>> class MyClass:
... __slots__ = ('my_member',)
...
>>> type('MySubClass', (MyClass,), dict(MyClass.__dict__))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 'my_member' in __slots__ conflicts with class variable
Type call to type()
above is the equivalent of what is happening behind the scenes in the typing
module.
This exception is caused by the fact that when you use __slots__
, the members you specify are automatically added into the type dict:
>>> MyClass.__slots__
['my_member']
>>> MyClass.__dict__
mappingproxy({..., 'my_member': <member 'my_member' of 'MyClass' objects>, ...})
When we do type('MySubClass', (MyClass,), dict(MyClass.__dict__))
, we are passing my_member
twice: once via MyClass.__slots__
, once via MyClass.__dict__
, and the type machinery is complaining about it.
There's not much you can do about it, other than avoiding using __slots__
or calling register()
instead of subclassing.
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