__slots__ 与泛型类中的类变量冲突

Eli*_*igo 5 python typing slots python-3.x python-3.5

我在 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]
Run Code Online (Sandbox Code Playgroud)

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

V = TestGeneric[int]
Run Code Online (Sandbox Code Playgroud)

我得到

ValueError: 'test' in __slots__ conflicts with class variable
Run Code Online (Sandbox Code Playgroud)

Generics 在没有插槽的类中使用了很多,因此我认为这个错误必须与__slots__. 此外,同一个类工作正常,如果你删除__slots__

And*_*ini 6

我会说这是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
Run Code Online (Sandbox Code Playgroud)

type()上面的类型调用相当于typing模块中幕后发生的事情。

此异常是由以下事实引起的:当您使用 时__slots__,您指定的成员会自动添加到类型 dict 中:

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

当我们这样做时type('MySubClass', (MyClass,), dict(MyClass.__dict__)),我们通过了my_member两次:一次通过MyClass.__slots__,一次通过MyClass.__dict__,类型机器抱怨它。

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