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

Python递归自定义Json类型赋值异常问题求助

递归JSON类型定义的类型检查问题及解决方法

问题描述

采用递归方式定义JSON类型时,出现了类型校验不一致的情况:直接使用字面量[0., 0.]赋值能通过检查,但用变量或[0.] * 2生成的列表赋值时却报错。按逻辑所有情况都应该通过校验,想知道这是不是bug,以及有没有无需给类型定义加冗余检测的解决办法。

代码示例

import typing as t

JsonType: t.TypeAlias = t.List['JsonValue'] | t.Mapping[str, 'JsonValue']
JsonValue: t.TypeAlias = str | int | float | None | JsonType


v0 = [0., 0.] # (variable) v0: list[float]
v1 = [0.] * 2 # (variable) v1: list[float]

test01: JsonType = {
  "v0": [0., 0.] # ok
}

test02: JsonType = {
  "v0": v0 # error
}

test11: JsonType = {
  "v": [0.] * 2 # error
}

test12: JsonType = {
  "v": v1 # error
}

错误信息

表达式类型 "dict[str, list[float]]" 与声明类型 "JsonType" 不兼容
类型 "dict[str, list[float]]" 与类型 "JsonType" 不兼容
  "dict[str, list[float]]" 与 "List[JsonValue]" 不兼容
  "dict[str, list[float]]" 与 "Mapping[str, JsonValue]" 不兼容
    类型参数 "_VT_co@Mapping" 是协变的,但 "list[float]" 不是 "JsonValue" 的子类型
      类型 "list[float]" 与类型 "JsonValue" 不兼容
        "list[float]" 与 "str" 不兼容
        "list[float]" 与 "int" 不兼容
        "list[float]" 与 "float" 不兼容
...PylancereportAssignmentType

问题原因

这不是bug,是静态类型检查器(比如Pylance)对字面量类型推导和变量类型推导的处理逻辑差异导致的:

  • 直接写字面量时,检查器会在赋值场景下尝试向上兼容递归定义的JsonValue类型,允许list[float]隐式匹配List[JsonValue];
  • 对于变量或[0.] * 2这类表达式,检查器会推导出精确的list[float]类型,而递归定义的JsonType里的List[JsonValue]要求元素必须是JsonValue,由于list[float]没有被显式关联到JsonValue,检查器无法自动完成兼容匹配。

解决方法(无需冗余类型检查)

1. 给变量显式标注JsonValue类型

直接给变量指定类型,让检查器明确它属于JsonValue:

import typing as t

JsonType: t.TypeAlias = t.List['JsonValue'] | t.Mapping[str, 'JsonValue']
JsonValue: t.TypeAlias = str | int | float | None | JsonType

v0: JsonValue = [0., 0.]
v1: JsonValue = [0.] * 2

test02: JsonType = {
  "v0": v0  # 正常通过检查
}

test12: JsonType = {
  "v": v1  # 正常通过检查
}

2. 用t.cast做临时类型转换

对于[0.] * 2这类临时表达式,用typing.cast告诉检查器该值符合JsonValue类型:

test11: JsonType = {
  "v": t.cast(JsonValue, [0.] * 2)
}

3. 调整类型定义以兼容协变

如果不想每次都标注或转换,可以修改类型定义,让列表的元素类型更宽松:

JsonType: t.TypeAlias = t.List[t.Union[JsonValue, float]] | t.Mapping[str, JsonValue]

这种方式会稍微扩大类型范围,需根据实际场景判断是否适用。


内容的提问来源于Stack Exchange,提问作者Craig Hicks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:53:11