Тип аннотации метода подкласса, который возвращает экземпляр класса - PullRequest
2 голосов
/ 07 июля 2019

У меня есть MeasurementBase абстрактный родительский класс, который имеет следующие функциональные возможности: (1) public serialize() & deserialize()

Я хотел бы реализовать общую логику для родительских открытых методов иопределить приватный _serialize() & _deserialize() аннотация.

Реализация базового класса выглядит следующим образом:

import json
from abc import ABC, abstractmethod
from typing import Any, Dict, Generic, TypeVar


TMeasurement = TypeVar("TMeasurement")


class MeasurementBase(ABC, Generic[TMeasurement]):

    def serialize(self) -> str:
        properties: Dict[str, Any] = {}
        properties["measurement_name"] = self.__class__.__name__
        properties["value"] = self._serialize()
        return json.dumps(properties)

    @abstractmethod
    def _serialize(self) -> Any:
        pass  # pragma: no cover

    @classmethod
    def deserialize(cls, json_str: str) -> TMeasurement:
        try:
            properties = json.loads(json_str)
            class_name = properties["measurement_name"]
            if cls.__name__ != class_name:
                raise KeyError()

            return cls._deserialize(properties["value"])
        except KeyError:
            raise KeyError()

    @classmethod
    @abstractmethod
    def _deserialize(cls, obj: Any) -> TMeasurement:
        pass  # pragma: no cover

Затем я создал новый подкласс с внутренним состоянием _val, который реализует абстрактные методы:

class MeasurementBaseMock(MeasurementBase["MeasurementBaseMock"]):
    def __init__(self, val: int) -> None:
        self._val = val

    def _serialize(self) -> Any:
        return self._val

    @classmethod
    def _deserialize(cls, obj: int) -> "MeasurementBaseMock":
        return MeasurementBaseMock(obj)

Затем при тестировании выше:

properties = {"value": 324, "measurement_name": MeasurementBaseMock.__name__}
measurement = MeasurementBaseMock.deserialize(json.dumps(properties))
print(measurement._val)

Я получил следующую ошибку:

error: "TMeasurement" has no attribute "_val"

Как аннотировать тип возврата _deserialize для поддержкипишущая машинка?

Вещи, которые я пытался: - Я пытался использовать TMeasurement = TypeVar("TMeasurement", bound = "MeasurementBase") - не работал и имел гораздо больше ошибок Mypy.- Я переместил инициализацию всего состояния в родительский класс - этот работал, но я предпочитаю не использовать такой дизайн.- Я также пробовал использовать аннотации cls, но с той же ошибкой.

Примечание: я использую mypy

> mypy --version
mypy 0.660
...