用类型值注释数据类类变量

zii*_*ima 5 python mypy python-dataclasses

我们有许多数据类,代表具有共同祖先的各种结果Result。然后,每个结果使用其自己的 子类提供其数据ResultData。但我们很难正确注释该案例。

我们想出了以下解决方案:

from dataclasses import dataclass
from typing import ClassVar, Generic, Optional, Sequence, Type, TypeVar


class ResultData:
    ...


T = TypeVar('T', bound=ResultData)


@dataclass
class Result(Generic[T]):
    _data_cls: ClassVar[Type[T]]
    data: Sequence[T]

    @classmethod
    def parse(cls, ...) -> T:
        self = cls()
        self.data = [self._data_cls.parse(...)]
        return self

class FooResultData(ResultData):
    ...

class FooResult(Result):
    _data_cls = FooResultData
Run Code Online (Sandbox Code Playgroud)

但它最近因 mypy error 停止工作ClassVar cannot contain type variables [misc]。它也反对 PEP 526,请参阅https://www.python.org/dev/peps/pep-0526/#class-and-instance-variable-annotations,我们之前错过了。

有没有办法正确注释这个案例?

zii*_*ima 1

最后,我只是_data_cls用基类替换了注释中的变量,并修复了子类的注释,如@rv.kvetch 在他的回答中指出的那样。

缺点是需要在每个子类中定义两次结果类,但在我看来,这比在属性中提取类更清晰。

完整的解决方案:

from dataclasses import dataclass
from typing import ClassVar, Generic, Optional, Sequence, Type, TypeVar


class ResultData:
    ...


T = TypeVar('T', bound=ResultData)


@dataclass
class Result(Generic[T]):
    _data_cls: ClassVar[Type[ResultData]]  # Fixed annotation here
    data: Sequence[T]

    @classmethod
    def parse(cls, ...) -> T:
        self = cls()
        self.data = [self._data_cls.parse(...)]
        return self

class FooResultData(ResultData):
    ...

class FooResult(Result[FooResultData]):  # Fixed annotation here
    _data_cls = FooResultData
Run Code Online (Sandbox Code Playgroud)