如何解决mypy报错:返回值类型不兼容(FancyCat与Self不匹配)
解决Mypy中Protocol与Self类型不匹配的报错
问题代码
from __future__ import annotations from typing import Protocol from typing_extensions import Self class Cat(Protocol): def add(self, other: Self) -> Self: ... def sub(self, other: Self) -> Self: ... class FancyCat(Cat): def __init__(self, value: int): self._value = value def add(self, other: Self) -> Self: return FancyCat(self._value + other._value) def sub(self, other: Self) -> Self: return FancyCat(self._value - other._value) fc = FancyCat(3) fc2 = FancyCat(4) fc.add(fc2)
报错信息
$ mypy t.py t.py:19: error: Incompatible return value type (got "FancyCat", expected "Self") [return-value] t.py:22: error: Incompatible return value type (got "FancyCat", expected "Self") [return-value] Found 2 errors in 1 file (checked 1 source file)
原因分析
你觉得Self就是FancyCat的理解没错,但Mypy对Protocol中的Self类型有更严格的校验:Self指代的是调用该方法的实例的实际类型,而非固定的FancyCat。比如如果有子类继承FancyCat,子类实例调用add方法时,按照Protocol的定义应该返回子类实例,而非FancyCat。直接返回FancyCat实例会破坏这种多态性预期,因此Mypy抛出报错。
解决方案
方案1:用type(self)创建实例(推荐)
这种写法符合里氏替换原则,无论FancyCat是否被继承,都能保证返回与调用者同类型的实例:
from __future__ import annotations from typing import Protocol from typing_extensions import Self class Cat(Protocol): def add(self, other: Self) -> Self: ... def sub(self, other: Self) -> Self: ... class FancyCat(Cat): def __init__(self, value: int): self._value = value def add(self, other: Self) -> Self: return type(self)(self._value + other._value) def sub(self, other: Self) -> Self: return type(self)(self._value - other._value) fc = FancyCat(3) fc2 = FancyCat(4) fc.add(fc2)
方案2:用cast强制类型转换(仅当确定无子类时使用)
如果可以保证FancyCat不会被继承,直接用cast告诉Mypy返回值符合Self类型:
from __future__ import annotations from typing import Protocol, cast from typing_extensions import Self class Cat(Protocol): def add(self, other: Self) -> Self: ... def sub(self, other: Self) -> Self: ... class FancyCat(Cat): def __init__(self, value: int): self._value = value def add(self, other: Self) -> Self: return cast(Self, FancyCat(self._value + other._value)) def sub(self, other: Self) -> Self: return cast(Self, FancyCat(self._value - other._value))
内容的提问来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

