#python #mypy #python-typing #python-dataclasses #abstract-base-class
Вопрос:
mypy v0.910 отвергает абстрактные классы данных в Python 3.9. Вот минимальный воспроизводимый пример:
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class Liquid(ABC):
@abstractmethod
def drip(self) -> None:
pass
Вот сообщение об ошибке:
$ mypy --python-version 3.9 so.py
so.py:4: error: Only concrete class can be given where "Type[Liquid]" is expected
Found 1 error in 1 file (checked 1 source file)
Как мне получить этот код для передачи mypy?
Примечания
Из выпуска mypy № 5374 я понял, что это ошибка в mypy, впервые замеченная в 2018 году и до сих пор не исправленная. Я полагаю, что люди должны использовать mypy с абстрактными классами данных, поэтому должен быть обходной путь или правильный способ определения или аннотирования класса. Что рекомендуется?
Основанием для сообщения об ошибке, по-видимому, является то, что mypy предполагает, что любой объект типа Type
может быть создан, но абстрактные классы не могут быть созданы. Это, по-видимому, ошибка, поскольку Type
определяется как объект класса, не обязательно конкретный объект класса (т. Е. Тот, который может быть создан).
Добавление # type: ignore
в строку, содержащую class Liquid
, не блокирует сообщение об ошибке. Поскольку код не содержит Type[Liquid]
, я полагаю, что он должен быть в коде, сгенерированном dataclass
. Type
устарел в Python 3.9, но, по-видимому dataclass
, генератор кода все еще генерирует его.
Комментарии:
1. Из любопытства, какова цель использования декоратора dataclass здесь?
2. @juanpa.arrivillaga Цель состоит только в том, чтобы сделать Минимальный воспроизводимый пример. Классы данных в моем производственном коде имеют атрибуты-члены. Я только что перепроверил, и пример не сработает, если я добавлю атрибут участника.
Ответ №1:
Создайте класс данных в виде миксина и позвольте классу ABC наследовать от него:
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass
class LiquidDataclassMixin:
my_var: str
class Liquid(ABC, LiquidDataclassMixin):
@abstractmethod
def drip(self) -> None:
pass
Это также работает с проверкой типа mypy. Я рекомендую не использовать # type: ignore
, так как это противоречит точке проверки типа. Взято из этого выпуска GitHub.
Комментарии:
1. Когда я впервые увидел этот подход, я был обеспокоен тем, что он создаст беспорядок, поскольку каждому абстрактному классу данных требуется отдельный класс смешивания. Но я только что просмотрел всю свою кодовую базу и нашел только четыре абстрактных класса данных, так что это определенно выполнимо. Спасибо!
Ответ №2:
Добавьте # type: ignore
в строку декоратора. Так что в вашем случае это было бы:
from abc import ABC, abstractmethod
from dataclasses import dataclass
@dataclass # type: ignore
class Liquid(ABC):
@abstractmethod
def drip(self) -> None:
pass