如何让Python json模块遇NaN时抛出JSONDecodeError而非ValueError?
解决Python JSON模块排除NaN时异常类型不一致的问题
默认情况下,在自定义parse_constant函数中抛出的ValueError不会被json模块自动转为JSONDecodeError,导致需要处理两种异常类型,且无法获取行号、位置等解析上下文信息。以下是两种可行的解决方法:
方案一:子类化JSONDecoder(推荐)
通过继承json.JSONDecoder并重写parse_constant方法,直接抛出包含精确位置信息的JSONDecodeError,完全贴合json模块的异常规范:
import json from json.decoder import JSONDecodeError class NoNaNDecoder(json.JSONDecoder): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.parse_constant = self._custom_parse_constant def _custom_parse_constant(self, constant_str: str): if constant_str == "NaN": # 获取解析器当前的位置和原始JSON文档 pos = self.scanner.pos raise JSONDecodeError( "NaN is not valid JSON", self.raw_decode_doc, pos ) # 其他常量(如Infinity、-Infinity)沿用默认处理逻辑 return super().parse_constant(constant_str) # 使用示例 some_json_string = '{"value": NaN}' try: json_content = json.loads(some_json_string, cls=NoNaNDecoder) except JSONDecodeError as e: print(f"解析错误:{e},行号:{e.lineno},列位置:{e.colno}")
这种方法能直接获取解析器的真实扫描位置,错误信息包含准确的行号和列号,是最可靠的实现方式。
方案二:包装json.loads调用(简单场景适用)
如果不想子类化解码器,可以在调用json.loads时捕获自定义的ValueError,手动构造JSONDecodeError。虽然无法获取解析器的精确位置,但可以通过正则匹配定位NaN的大致位置:
import json from json.decoder import JSONDecodeError import re def loads_no_nan(json_str: str): def parse_constant(constant_str: str): if constant_str == "NaN": raise ValueError("NaN is not valid JSON") return float(constant_str) try: return json.loads(json_str, parse_constant=parse_constant) except ValueError as e: if str(e) == "NaN is not valid JSON": # 匹配JSON中的NaN常量(排除字符串内的NaN) match = re.search(r'(?<!")\bNaN\b(?!")', json_str) if match: pos = match.start() raise JSONDecodeError(str(e), json_str, pos) from e # 非自定义的ValueError原样抛出 raise # 使用示例 some_json_string = '{"value": NaN}' try: json_content = loads_no_nan(some_json_string) except JSONDecodeError as e: print(f"解析错误:{e}")
注意:该方法的正则匹配可能存在边缘情况(如嵌套结构中的NaN),仅适合简单场景使用。
内容的提问来源于stack exchange,提问作者Olivier Desenfans
相关产品推荐
相关产品推荐

