__slots__ 与通用 class 中的 class 变量冲突

__slots__ conflicts with a class variable in a generic class

Python 的打字系统和 __slots__ 之间存在冲突。这是一个可重现的小例子。

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]

现在每当我尝试指定内容类型时,例如

V = TestGeneric[int]

我明白了

ValueError: 'test' in __slots__ conflicts with class variable

我在 classes 中经常使用 Generics 而没有插槽,因此我认为这个错误必须与 __slots__ 相关联。此外,如果删除 __slots__

,相同的 class 也可以正常工作

我会说这是 typing 模块中的一个错误,它在创建新类型时没有正确考虑 __slots__

这个问题可以用这个非常短的例子重现:

>>> 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() 的类型调用等同于 typing 模块幕后发生的事情。

这个异常是因为当你使用__slots__时,你指定的成员会自动添加到类型dict中:

>>> MyClass.__slots__
['my_member']
>>> MyClass.__dict__
mappingproxy({..., 'my_member': <member 'my_member' of 'MyClass' objects>, ...})

当我们执行 type('MySubClass', (MyClass,), dict(MyClass.__dict__)) 时,我们传递了 my_member 两次:一次通过 MyClass.__slots__,一次通过 MyClass.__dict__,并且类型机器正在抱怨它。

除了避免使用 __slots__ 或调用 register() 而不是子类化之外,您无能为力。