You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 18:42:30