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__
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.