json.dumps()默认不支持set/frozenset/bytes,需通过default参数或自定义JSONEncoder处理:set/frozenset转list,bytes用base64编码或UTF-8解码,且须确保嵌套元素本身可序列化。

json.dumps() 默认不支持 set / frozenset / bytes 怎么办
直接调用 json.dumps() 序列化含 set、frozenset 或 bytes 的对象会抛出 TypeError: Object of type set is not JSON serializable。这不是 bug,而是 JSON 标准本身不定义这些类型——Python 的 json 模块严格遵循该限制,不会自动降级或猜测意图。
用 default 参数把不可序列化对象转成 dict/list/str
default 是最常用也最可控的方式:它接收一个函数,当遇到无法序列化的对象时,由你决定返回什么合法的 JSON 类型(如 list、str、dict)。
典型做法:
-
set和frozenset→ 转为list(保持元素可序列化前提下) -
bytes→ 先用.decode('utf-8')(若确定是 UTF-8),或用base64.b64encode(x).decode('ascii')保全二进制语义 - 其他未知类型建议抛出原异常,避免静默错误
示例:
import json import base64def json_fallback(obj): if isinstance(obj, (set, frozenset)): return list(obj) elif isinstance(obj, bytes): return base64.b64encode(obj).decode('ascii') raise TypeError(f"Object of type {type(obj).name} is not JSON serializable")
data = {"tags": {"python", "web"}, "payload": b"\x00\x01\xff"} json.dumps(data, default=json_fallback)
→ '{"tags": ["python", "web"], "payload": "AAH/" }'
注意 bytes 编码方式选择:decode vs base64
对 bytes 处理要分场景:
- 若明确是文本(如 UTF-8 编码的字符串),用
obj.decode('utf-8')更简洁可读 - 若可能是任意二进制数据(如加密密钥、图片片段),必须用
base64,否则会因非法字节抛UnicodeDecodeError - 别用
str(obj)或obj.hex()—— 前者生成类似b'\\x00'的字符串,后者长度翻倍且不易反解
自定义 JSONEncoder 子类适合复用或组合逻辑
当项目中多处需要一致的序列化规则,或者要同时处理多种自定义类型(如 datetime + set),继承 json.JSONEncoder 更清晰:
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, (set, frozenset)):
return sorted(obj) # 可选:排序让输出稳定
elif isinstance(obj, bytes):
return base64.b64encode(obj).decode('ascii')
return super().default(obj)
json.dumps(data, cls=CustomEncoder)
注意:default 函数和 cls 不能共存;优先用 cls 可以复用、可继承、便于单元测试。
真正容易被忽略的是:无论用哪种方式,都得确保 set 里的每个元素本身可被 JSON 序列化——比如 {1, {"a": 2}} 会失败,因为 dict 不能直接放进 set 再靠 fallback 处理;这种嵌套需提前规整或改用其他结构。










