如何为包含自定义类对象的复杂类编写自定义JSON解码器?
为包含自定义类的Edge类编写JSON解码器
哈哈,我懂你现在的困境——已经搞定了Edge列表的JSON序列化,反序列化却不知道怎么下手对吧?别慌,咱们一步步来解决这个问题,核心思路就是在序列化时给自定义类打上标识,反序列化时根据标识还原对象。
先理清楚前提(假设你的类结构大概是这样)
首先我先基于你描述的场景,还原一下Actor、Movie和Edge类的基本结构(soup属性因为无法序列化,咱们序列化时会忽略它):
from bs4 import BeautifulSoup import json class Actor: def __init__(self, name, soup: BeautifulSoup): self.name = name self.soup = soup class Movie: def __init__(self, title, soup: BeautifulSoup): self.title = title self.soup = soup class Edge: def __init__(self, actor: Actor, movie: Movie): self.actor = actor self.movie = movie
第一步:回顾你的自定义编码器(确保带类型标识)
你已经写好的编码器,一定要给每个自定义类加上__type__字段,这是解码器识别对象类型的关键。比如你的编码器可以是这样:
class EdgeEncoder(json.JSONEncoder): def default(self, obj): # 处理Edge对象 if isinstance(obj, Edge): return { "__type__": "Edge", "actor": self.default(obj.actor), "movie": self.default(obj.movie) } # 处理Actor对象 elif isinstance(obj, Actor): return { "__type__": "Actor", "name": obj.name # soup属性无法序列化,直接忽略,后续可以按需重新获取 } # 处理Movie对象 elif isinstance(obj, Movie): return { "__type__": "Movie", "title": obj.title # 同样忽略soup } # 其他类型交给父类处理 return super().default(obj)
第二步:编写自定义解码器(用object_hook更灵活)
反序列化的核心是用json.loads()的object_hook参数,它会在解析每个JSON字典时触发,我们可以根据__type__字段来还原对应的类实例:
def edge_decoder(obj): # 先判断是不是Edge类型 if "__type__" in obj and obj["__type__"] == "Edge": # 先还原Actor实例 actor = edge_decoder(obj["actor"]) # 再还原Movie实例 movie = edge_decoder(obj["movie"]) # 返回Edge实例(soup暂时传None,后续可以根据name/title重新爬取) return Edge(actor, movie) # 还原Actor实例 elif "__type__" in obj and obj["__type__"] == "Actor": return Actor(name=obj["name"], soup=None) # 还原Movie实例 elif "__type__" in obj and obj["__type__"] == "Movie": return Movie(title=obj["title"], soup=None) # 非自定义类的对象直接返回 return obj
第三步:测试序列化+反序列化流程
现在咱们来验证一下整个流程是否能正常工作:
# 创建测试对象 test_actor = Actor(name="汤姆·汉克斯", soup=None) test_movie = Movie(title="阿甘正传", soup=None) test_edge = Edge(test_actor, test_movie) # 序列化Edge列表到JSON字符串 json_str = json.dumps([test_edge], cls=EdgeEncoder) print("序列化后的JSON:", json_str) # 反序列化JSON字符串回Edge列表 restored_edges = json.loads(json_str, object_hook=edge_decoder) print("\n反序列化后的结果:") print(f"演员姓名:{restored_edges[0].actor.name}") print(f"电影名称:{restored_edges[0].movie.title}")
关键注意点
- 类型标识是核心:一定要在编码器里给每个自定义类加上
__type__,否则解码器不知道该还原成哪个类 - 不可序列化属性的处理:像BeautifulSoup的soup对象无法被JSON序列化,所以编码器里要忽略它,解码器里可以传None,之后如果需要可以根据name/title重新爬取页面生成soup
- 嵌套处理:因为Edge里包含Actor和Movie,所以解码器要递归处理嵌套的字典,确保所有自定义类都能被正确还原
内容的提问来源于stack exchange,提问作者lmotl3
相关产品推荐
相关产品推荐

