为何Mypy判定JSON子集类型无效?子类返回类型兼容问题
子类返回嵌套JSON类型时Mypy报错的原因与解决办法
我定义了返回JSON类型的基类JsonReturner,子类返回更具体的嵌套JSON类型,但Mypy报错提示返回类型不兼容,疑惑是类型概念误解还是类型检查的实现边界问题。
完整示例代码
from typing import TypeAlias JSON: TypeAlias = dict[str, "JSON"] | list["JSON"] | str | int | float | bool | None class JsonReturner: def return_json(self) -> JSON: raise NotImplementedError("abstract base class") class ListJsonReturner(JsonReturner): def return_json(self) -> list[JSON]: return [] class DictJsonReturner(JsonReturner): def return_json(self) -> dict[str, JSON]: return {} class ListDictJsonReturner(JsonReturner): def return_json(self) -> list[dict[str, JSON]]: return [] class DictListJsonReturner(JsonReturner): def return_json(self) -> dict[str, list[JSON]]: return {}
Mypy报错信息
$ mypy jsontypes.py jsontypes.py:27: error: Return type "List[Dict[str, JSON]]" of "return_json" incompatible with return type "JSON" in supertype "JsonReturner" [override] jsontypes.py:33: error: Return type "Dict[str, List[JSON]]" of "return_json" incompatible with return type "JSON" in supertype "JsonReturner" [override]
原因分析
这既不是类型概念误解,也不完全是类型检查的边界问题,核心是Mypy对递归联合类型别名的嵌套子类型的兼容推导存在局限:
- 里氏替换原则要求子类方法返回类型必须是父类返回类型的协变类型,
list[dict[str, JSON]]确实是JSON的子集,但Mypy只能直接识别JSON顶层联合成员(比如list[JSON]、dict[str, JSON])与JSON的兼容关系; - 对于深层嵌套的类型(如
list[dict[str, JSON]]),Mypy无法自动递归解析它属于JSON类型的一部分,因此判定返回类型不兼容。
解决方案
方案1:使用泛型协变(推荐)
通过定义协变的TypeVar,让基类支持泛型返回类型,子类指定具体的嵌套JSON类型,既满足类型检查,又保留具体类型信息:
from typing import TypeAlias, TypeVar, Generic JSON: TypeAlias = dict[str, "JSON"] | list["JSON"] | str | int | float | bool | None # 定义协变的TypeVar,绑定到JSON类型 T = TypeVar("T", bound=JSON, covariant=True) class JsonReturner(Generic[T]): def return_json(self) -> T: raise NotImplementedError("abstract base class") class ListJsonReturner(JsonReturner[list[JSON]]): def return_json(self) -> list[JSON]: return [] class DictJsonReturner(JsonReturner[dict[str, JSON]]): def return_json(self) -> dict[str, JSON]: return {} class ListDictJsonReturner(JsonReturner[list[dict[str, JSON]]]): def return_json(self) -> list[dict[str, JSON]]: return [] class DictListJsonReturner(JsonReturner[dict[str, list[JSON]]]): def return_json(self) -> dict[str, list[JSON]]: return {}
方案2:显式兼容声明(不推荐)
如果不想用泛型,可以将子类返回类型声明为JSON,内部保留具体类型,或者用cast强制类型转换,但会丢失部分类型检查的严谨性:
# 方式1:返回类型声明为JSON class ListDictJsonReturner(JsonReturner): def return_json(self) -> JSON: result: list[dict[str, JSON]] = [] return result # 方式2:使用cast from typing import cast class DictListJsonReturner(JsonReturner): def return_json(self) -> JSON: return cast(JSON, {})
内容的提问来源于stack exchange,提问作者wrgrs
相关产品推荐
相关产品推荐

