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

自定义json.dumps序列化行为:优化非标准JSON生成方案

更Pythonic的非标准JSON序列化实现

我有一个字典{"a": "hello", "b": b"list"}:

  • 'a' 是字符串类型
  • 'b' 是字节字符串类型

我需要将该字典序列化为如下非标准JSON格式字符串:'{"a": "hello", "b": list}'

目前我写了下面的方法,虽然能正常运行,但用字符串替换的方式显得有点取巧:

def stringify(obj):
    def my(obj):
        if isinstance(obj,bytes):
            return "<::%s::>" % obj.decode()
    return json.dumps(obj, default=my).replace('"<::',"").replace('::>"',"")

(添加<::和::>是为了序列化后通过字符串替换得到预期结果)

我想知道有没有更符合Python风格的实现方式?

补充要求

重写后的stringify函数需要满足以下断言:

assert stringify( dict(a="hello",b=b"byte") ) == '{"a": "hello", "b": byte}'
assert stringify( ["hello", b"world"] ) == '["hello", world]'
assert stringify( "hello" ) == '"hello"'
assert stringify( b"world" ) == "world"

方案一:自定义JSONEncoder子类(标准扩展方式)

Python的json模块提供了JSONEncoder基类,允许我们通过继承它来定制序列化逻辑,这是官方推荐的扩展方式,比字符串替换更优雅可靠。

实现代码如下:

import json

class CustomByteEncoder(json.JSONEncoder):
    def encode(self, obj):
        # 单独处理最外层是字节串的情况
        if isinstance(obj, bytes):
            return obj.decode()
        # 先按标准JSON序列化,再替换字节串的标记
        standard_json = super().encode(obj)
        return standard_json.replace('"__BYTE_MARKER__:', '').replace(':__BYTE_MARKER__"', '')
    
    def default(self, obj):
        if isinstance(obj, bytes):
            # 给字节串添加唯一标记,避免和普通字符串混淆
            return f'__BYTE_MARKER__:{obj.decode()}:__BYTE_MARKER__'
        # 其他类型交给父类处理
        return super().default(obj)

def stringify(obj):
    return CustomByteEncoder().encode(obj)

测试所有断言,均能通过:

assert stringify( dict(a="hello",b=b"byte") ) == '{"a": "hello", "b": byte}'
assert stringify( ["hello", b"world"] ) == '["hello", world]'
assert stringify( "hello" ) == '"hello"'
assert stringify( b"world" ) == "world"

这种方式的优势在于:

  • 遵循Python标准的JSON扩展规范,逻辑清晰易读
  • 自定义标记__BYTE_MARKER__可以有效避免和普通字符串内容冲突,比简单的<::更安全
  • 后续可以轻松扩展其他自定义类型的序列化逻辑

方案二:递归遍历构建字符串(完全自定义)

如果不想依赖json.dumps的基础序列化,也可以直接递归遍历对象结构,逐个生成对应的字符串,完全掌控序列化流程:

import json

def stringify(obj):
    if isinstance(obj, str):
        return json.dumps(obj)  # 字符串直接用标准JSON转义处理
    elif isinstance(obj, bytes):
        return obj.decode()  # 字节串直接转成无引号的字符串
    elif isinstance(obj, dict):
        # 遍历字典键值对,分别序列化后拼接
        items = []
        for key, value in obj.items():
            key_str = json.dumps(key)
            val_str = stringify(value)
            items.append(f"{key_str}: {val_str}")
        return "{" + ", ".join(items) + "}"
    elif isinstance(obj, list):
        # 遍历列表元素,序列化后拼接
        elements = [stringify(item) for item in obj]
        return "[" + ", ".join(elements) + "]"
    else:
        # 其他基础类型(数字、布尔、None)用标准JSON处理
        return json.dumps(obj)

这个方案完全不需要字符串替换,直接根据每个元素的类型生成对应格式的字符串,所有断言同样可以通过。

优势在于:

  • 序列化流程完全可控,没有中间步骤的字符串替换操作
  • 每个类型的处理逻辑一目了然,便于调试和修改
  • 不会出现标记符冲突的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 14:02:09