如何用Python标准json库序列化含Decimal的dataclass?
解决Dataclass含Decimal字段的JSON序列化问题
你遇到的问题核心是:自定义的JSONEncoder只处理了Decimal类型,但**TransactionData实例本身不属于JSON原生可序列化类型**,所以需要同时处理dataclass实例和Decimal的序列化逻辑。以下是两种基于标准json库的可行方案:
方案一:先转字典再用自定义Encoder
先通过dataclasses.asdict()把dataclass实例转为普通字典,再用自定义Encoder处理字典里的Decimal字段:
from dataclasses import dataclass, asdict import json from decimal import Decimal @dataclass class TransactionData: amount: Decimal description: str # 自定义Encoder处理Decimal class DecimalEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, Decimal): # 金融场景推荐转字符串保留精度,也可按需转float:return float(obj) return str(obj) return super().default(obj) # 实例化并序列化 tx = TransactionData(amount=Decimal('123.45'), description="超市采购") json_result = json.dumps(asdict(tx), cls=DecimalEncoder) print(json_result) # 输出:{"amount": "123.45", "description": "超市采购"}
方案二:在自定义Encoder中同时处理Dataclass
如果不想每次手动调用asdict(),可以在Encoder里直接识别dataclass实例并自动转字典:
from dataclasses import dataclass, is_dataclass, asdict import json from decimal import Decimal @dataclass class TransactionData: amount: Decimal description: str class CustomJSONEncoder(json.JSONEncoder): def default(self, obj): # 先处理dataclass实例 if is_dataclass(obj): return asdict(obj) # 再处理Decimal if isinstance(obj, Decimal): return str(obj) # 其他类型交给父类处理 return super().default(obj) # 直接序列化dataclass实例 tx = TransactionData(amount=Decimal('678.90'), description="房租") json_result = json.dumps(tx, cls=CustomJSONEncoder) print(json_result) # 输出:{"amount": "678.90", "description": "房租"}
关键说明
- 之前报错的原因:
json.dumps()默认只认识JSON原生类型(字符串、数字、列表、字典等),dataclass实例不属于这些类型,所以即使处理了Decimal,依然会报错。 - Decimal转字符串是为了避免浮点数精度丢失,若业务场景允许精度损失,也可以改为
return float(obj)。
内容的提问来源于stack exchange,提问作者clattenburg cake
相关产品推荐
相关产品推荐

