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

如何让json.dumps()以科学计数法序列化整数与浮点数?

解决json.dumps()重载整数/浮点数序列化的问题

你遇到的核心问题是:json.JSONEncoder的default()方法只在处理默认编码器认不出来的类型时才会触发,而int、float是JSON原生支持的基础类型,所以你写的ScientificNotationNumbers里的逻辑根本不会被调用。

下面给你三种可行的解决方法:

方案一:先预处理数据,把数字转成科学计数法字符串

先递归遍历你的数据结构(不管是字典还是嵌套的列表、对象属性),把所有int/float转成指定格式的字符串,再用json.dumps()序列化就行:

import json
from typing import Any

def convert_numbers_to_sci(data: Any) -> Any:
    if isinstance(data, dict):
        return {k: convert_numbers_to_sci(v) for k, v in data.items()}
    elif isinstance(data, list):
        return [convert_numbers_to_sci(item) for item in data]
    elif isinstance(data, (int, float)):
        return "{:.2e}".format(data)
    else:
        return data

# 你的类用法示例
class YourClass:
    def __init__(self):
        self.data = {"big_num": 123456789, "small_num": 0.0000123, "text": "示例文本"}
    
    def __str__(self) -> str:
        # 先转换当前对象的属性字典
        processed_data = convert_numbers_to_sci(vars(self))
        return json.dumps(processed_data, indent=4, ensure_ascii=False)

obj = YourClass()
print(obj)

方案二:重写编码器的encode方法,把转换逻辑封装进去

把数据转换逻辑直接写在自定义编码器的encode()方法里,这样调用方式和你原来的写法完全一致,不用额外处理数据:

import json
from typing import Any

class ScientificNotationNumbers(json.JSONEncoder):
    def encode(self, obj: Any) -> str:
        # 内部递归处理数字类型
        def convert(item):
            if isinstance(item, (int, float)):
                return "{:.2e}".format(item)
            elif isinstance(item, dict):
                return {k: convert(v) for k, v in item.items()}
            elif isinstance(item, list):
                return [convert(i) for i in item]
            else:
                return item
        
        processed_obj = convert(obj)
        return super().encode(processed_obj)

# 你的类用法示例
class YourClass:
    def __init__(self):
        self.data = {"big_num": 123456789, "small_num": 0.0000123, "text": "示例文本"}
    
    def __str__(self) -> str:
        return json.dumps(self, indent=4, ensure_ascii=False, cls=ScientificNotationNumbers)

obj = YourClass()
print(obj)

方案三:重写编码器的_iterencode方法,对接底层逻辑

如果想更贴近编码器的原生工作流程,可以重写_iterencode()方法,直接拦截数字类型的序列化过程:

import json
from typing import Any, Iterator

class ScientificNotationNumbers(json.JSONEncoder):
    def _iterencode(self, obj: Any, markers=None) -> Iterator[str]:
        if isinstance(obj, (int, float)):
            # 注意要加引号,因为要转成JSON字符串类型
            yield "\"{:.2e}\"".format(obj)
        else:
            # 其他类型交给父类处理
            yield from super()._iterencode(obj, markers)

# 你的类用法示例
class YourClass:
    def __init__(self):
        self.data = {"big_num": 123456789, "small_num": 0.0000123, "text": "示例文本"}
    
    def __str__(self) -> str:
        return json.dumps(self, indent=4, ensure_ascii=False, cls=ScientificNotationNumbers)

obj = YourClass()
print(obj)

三种方案的特点

  • 方案一逻辑简单直白,适合数据结构不复杂的场景,不用修改编码器。
  • 方案二把转换逻辑封装在编码器内部,保持调用方式不变,符合面向对象的封装思路。
  • 方案三直接对接编码器的底层迭代逻辑,效率稍高,但要注意手动拼接JSON字符串的引号(因为要把数字转成字符串类型)。

内容的提问来源于stack exchange,提问作者UsayHi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:25:23