Как получить абстрактный класс данных для передачи mypy?

#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