JSONDecoder默认不支持NaN和Infinity,因JSON标准禁止这些值;可通过object_hook或parse_float(需strict=False)实现兼容解析,但编码时仍需自定义处理。

JSONDecoder 默认不支持 NaN 和 Infinity
Python 的 json.JSONDecoder 在解析时遇到 NaN、Infinity 或 -Infinity 会直接报错:ValueError: Invalid value encountered: NaN(或类似提示)。这不是 bug,而是 JSON 标准本身禁止这些值 —— 它们不属于 RFC 7159 合法的 JSON 数字。
但实际中,不少后端(尤其是 JavaScript 环境)会输出带这些值的“类 JSON”字符串。若你必须接收并解析这类输入,就得绕过标准校验。
用 object_hook + float() 强转是最简方案
核心思路:在解析完每个对象(dict)后,遍历其所有字符串值,对匹配 "NaN"、"Infinity"、"-Infinity" 的项尝试用 float() 转换。Python 的 float() 原生支持这些字面量。
示例实现:
import jsondef handle_nan_inf(obj): for key, value in obj.items(): if isinstance(value, str): if value in ("NaN", "Infinity", "-Infinity"): obj[key] = float(value) return obj
data = '{"x": "NaN", "y": "Infinity", "z": 42}' result = json.loads(data, object_hook=handle_nan_inf)
result == {'x': nan, 'y': inf, 'z': 42}
- 仅作用于 dict 层级,不会递归处理嵌套 list 中的字符串;如需全覆盖,改用
object_hook+ 深度遍历,或换用parse_float - 注意
float("NaN")返回的是float('nan'),它不等于自身(nan == nan为False),后续判断要用math.isnan() - 此方式不改变原始 JSON 字符串结构,只在解析后做一次修正,开销小
用 parse_float 捕获所有数字字面量(含非法格式)
parse_float 参数会在 JSON 解析器遇到任何数字 token 时调用,包括那些本该失败的 NaN 字符串 —— 只要它们没被预校验拦住。关键在于:**必须配合 strict=False**,否则解析器在 tokenize 阶段就抛错了。
示例:
import jsondef robust_float(s): try: return float(s) except ValueError:
可选:记录未知格式,或返回 None/0
return float('nan')data = '{"a": NaN, "b": Infinity}' result = json.loads(data, parse_float=robust_float, strict=False)
result == {'a': nan, 'b': inf}
-
strict=False是前提,否则parse_float根本不会被触发 -
parse_float接收的是原始 token 字符串(如"NaN"),不是已解析的数字,所以能捕获非法字面量 - 它对所有数字位置生效(dict 值、list 元素、嵌套任意深度),比
object_hook更彻底 - 副作用:也会处理合法数字字符串(如
"123"),若你的robust_float有额外逻辑,需先判断是否为特殊字面量
别忽略 JSONEncoder 的反向兼容问题
能解析 NaN 不代表能原样输出。Python 的 json.JSONEncoder 默认拒绝编码 float('nan'),会报 ValueError: Out of range float values are not JSON compliant。
- 若需导出,必须自定义
default或继承JSONEncoder,例如:default=lambda x: None if math.isnan(x) else x - 更常见做法是提前清洗数据:入库/传输前把
nan/inf替换为None或特定哨兵值(如"__NaN__"),避免序列化阶段出问题 - 前后端约定比强行兼容更可靠 —— 比如统一用
null表示缺失,用字符串"inf"表示无穷大
真正麻烦的从来不是怎么读进来,而是读进来之后,要不要、以及能不能再安全地写出去。










