python - mypy 通用子类导致不兼容的类型

标签 python generics inheritance mypy invariance

我正在尝试使用类型提示实现幺半群。为此,我写了:

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))

我收到错误:“append”的参数 1 与父类(super class)型“Monoid”不兼容。由于 ListMonoid 的适当子类,我希望它能够键入。我做错了什么?

最佳答案

好吧,您的 List不是 Monoid 的适当子类型。毕竟,您声明所有 Monoid 都必须有一个 append 方法,该方法可以接受任意 Monoid 或 Monoid 的子类——那么,为什么可以缩小 List 使其 append 只能接受特定的 List ?

这违反了 Liskov substitution principle .

您可以使用 generic self 解决此特定情况。 :

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

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

现在,您表示 Monoid 的所有子类都必须实现一个 append 方法,该方法专门接受该子类的任何类型。使用这个新版本的 Monoid,您的 List 类现在是类型安全的。

关于python - mypy 通用子类导致不兼容的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46991489/

相关文章:

python - 查找并替换列表中的字符串 - Python

java - 传递泛型作为方法的参数

c# - 是否有 C++ std::is_same 类模板的 C# 类似物?

javascript - 调用子类函数时调用父类(super class)函数

python - 如何在 Tkinter 中切换到不同的框架?

Python坐标转换ECI到ECEF

python - 使用 os.scandir() 引发 AttributeError : __exit__

c# - 将泛型与可能是值或引用类型的 null 进行比较?

c++ - C++ 中的继承和模板

java - 从孙类调用父类构造函数,调用父类或祖父类构造函数?