Универсальный подкласс 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 теперь безопасен для типов.