跳转到主内容
极星编程网:以代码为星,赴技术山海!

json.dumps() 如何自定义序列化 set / frozenset

json.dumps()默认不支持set/frozenset,需通过default参数或自定义JSONEncoder处理;default最轻量,但需注意无序性、无限循环及嵌套未处理问题。 js on.dumps() 默认不支持 set / frozenset 直接传
set
或
frozenset
给
json.dumps()
会报
TypeError: Object of type set is not JSON serializable
。JSON 标准本身没有对应集合的类型,Python 的
json
模块默认只认
dict
、
list
、
str
、
int
、
float
、
bool
和
None
。 用 default 参数把 set 转成 list 最常用、最轻量的做法是通过
default
参数提供一个 回调函数 ,对不认识的类型做转换:
import json

def json_default(obj): if isinstance(obj, (set, frozenset)): return list(obj) raise TypeError(f"Object of type {type(obj).name} is not JSON serializable")

data = {"tags": {"python", "web", "api"}, "readonly": frozenset([1, 2, 3])} json_str = json.dumps(data, default=json_default, sort_keys=True)

→ {"readonly": [1, 2, 3], "tags": ["api", "python", "web"]}

default
函数只在遇到无法序列化的对象时被调用,不影响其他类型 返回
list(obj)
是安全的,但注意:
set
无序,转成
list
后顺序不保证(如需稳定顺序,可加
sorted()
) 不要在
default
中返回原始
obj
或递归调用
json.dumps()
,否则会无限循环 需要保持集合语义?考虑自定义 encoder 类 如果下游解析器能配合改造,想显式区分“这是个集合”,可以继承
json.JSONEncoder
并重写
encode
或
default
:
class SetEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, set): return {"__set__": True, "values": list(obj)} if isinstance(obj, frozenset): return {"__frozenset__": True, "values": list(obj)} return super().default(obj)

json.dumps({"s": {1, 2}}, cls=SetEncoder)

php版微信js-sdk支付接口类

php版微信js-sdk支付接口类

下载

→ {"s": {"set": true, "values": [1, 2]}}

这种格式增加了元信息,但要求解析端也识别
__set__
字段并还原 不能和
default
参数混用(
cls
优先级更高) 若数据里还有其他自定义类型,记得在
default
末尾调用
super().default(obj)
,否则会丢弃默认行为 注意嵌套结构和不可哈希元素
set
里如果包含不可 JSON 序列化的对象(比如另一个
set
、函数、或自定义类实例),仅靠上面的
default
还不够:
{1, {2, 3}}
会失败,因为内层
set
在外层
list(obj)
时才触发序列化,但此时已脱离
default
控制范围 正确做法是确保
default
能递归处理——但
json.dumps()
不提供递归钩子,所以得手动扁平化或预处理 更稳妥的方式是:在调用
json.dumps()
前,用 递归函数 把所有
set
/
frozenset
替换为
list
,再 dump 真正容易被忽略的是:你以为只改了顶层
set
就万事大吉,结果数据嵌套三层后某个字典的值仍是未处理的
frozenset
,错误才冒出来。

相关文章