Универсальный подкласс mypy приводит к несовместимым типам

Я играю с реализацией моноидов с подсказками типа. Для этого я написал:

M = TypeVar('M')

class Monoid(Generic[M]):
    ...
    def append(self, m: 'Monoid[M]') -> 'Monoid[M]':
        raise NotImplementedError()

При использовании этого в подклассе, например

A = TypeVar('A')

class List(Monoid[A], Generic[A]):
    def __init__(self, *values: A) -> None:
        self._values = tuple(values)
    ...
    def append(self, m: 'List[A]') -> 'List[A]':
        return List(*(self.values + m.values))

я получил error: Argument 1 of "append" incompatible with supertype "Monoid", поскольку List правильный подкласс MonoidЯ ожидаю, что это будет в состоянии печатать. Что я делаю неправильно?

1 ответ

Решение

Ну твой List класс не является правильным подтипом Monoid. В конце концов, вы заявили, что все моноиды должны иметь метод добавления, который может принимать любой произвольный моноид или подкласс моноида - так, почему это нормально, чтобы сузить список так, чтобы его append может принять только конкретно список?

Это нарушение принципа подстановки Лискова.

Вы можете обойти этот конкретный случай, используя общий self:

M = TypeVar('M')
T = TypeVar('T')

class Monoid(Generic[M]):
    ...
    def append(self: T, m: T) -> T:
        raise NotImplementedError()

Теперь вы выражаете, что все подклассы Monoid должен реализовать append метод, который принимает конкретно, что это за тип подкласса. С этой новой версией Monoid ваш класс List теперь безопасен для типов.

Другие вопросы по тегам