如何序列化包含PlayerElo类实例的字典以实现JSON的保存与加载?
解决自定义PlayerElo对象的JSON序列化问题
遇到自定义对象没法直接JSON序列化的情况太常见了,核心问题就是JSON模块不知道怎么把你的PlayerElo对象转换成它能识别的基本数据类型。这里给你两种实用的解决方案,你可以根据自己的代码结构选:
方案一:自定义JSON编码器和解码器
这种方法不用改动你的PlayerElo类太多,只需要写一个编码器告诉JSON怎么处理你的对象,再写一个解码器把JSON转回来。
序列化(保存)代码
import json class PlayerElo: """ 用于表示Elo评分系统中的玩家类 """ def __init__(self, name: str, id: str, rating): self.id = id self.name = name self.eloratings = {0: 1500} self.elomatches = {0: 0} self.initialrating = rating # 自定义编码器,处理PlayerElo对象 class PlayerEloEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, PlayerElo): # 把对象的所有属性打包成字典,加个类型标记方便后续识别 return { '__type__': 'PlayerElo', 'id': obj.id, 'name': obj.name, 'eloratings': obj.eloratings, 'elomatches': obj.elomatches, 'initialrating': obj.initialrating } # 其他类型交给默认逻辑处理 return super().default(obj) # 准备数据并保存到文件 playersElo = { 1: PlayerElo("Alice", "player_1", 1500), 2: PlayerElo("Bob", "player_2", 1500) } with open('players_elo.json', 'w', encoding='utf-8') as f: json.dump(playersElo, f, cls=PlayerEloEncoder, indent=4)
反序列化(加载)代码
def player_elo_decoder(obj): # 识别我们标记的类型,把字典转回PlayerElo对象 if obj.get('__type__') == 'PlayerElo': player = PlayerElo(obj['name'], obj['id'], obj['initialrating']) player.eloratings = obj['eloratings'] player.elomatches = obj['elomatches'] return player return obj # 从文件加载并转换 with open('players_elo.json', 'r', encoding='utf-8') as f: loaded_players = json.load(f, object_hook=player_elo_decoder) # 验证一下 print(loaded_players[1].name) # 输出Alice print(loaded_players[2].eloratings) # 输出{0: 1500}
方案二:给PlayerElo类添加序列化/反序列化方法
这种方法把序列化逻辑封装在类内部,更符合面向对象的设计,代码也更整洁。
import json class PlayerElo: """ 用于表示Elo评分系统中的玩家类 """ def __init__(self, name: str, id: str, rating): self.id = id self.name = name self.eloratings = {0: 1500} self.elomatches = {0: 0} self.initialrating = rating # 把对象转成可序列化的字典 def to_dict(self): return { 'id': self.id, 'name': self.name, 'eloratings': self.eloratings, 'elomatches': self.elomatches, 'initialrating': self.initialrating } # 从字典创建对象的类方法 @classmethod def from_dict(cls, data): player = cls(data['name'], data['id'], data['initialrating']) player.eloratings = data['eloratings'] player.elomatches = data['elomatches'] return player # 保存数据 playersElo = { 1: PlayerElo("Alice", "player_1", 1500), 2: PlayerElo("Bob", "player_2", 1500) } # 先把每个PlayerElo转成字典 serializable_data = {k: v.to_dict() for k, v in playersElo.items()} with open('players_elo.json', 'w', encoding='utf-8') as f: json.dump(serializable_data, f, indent=4) # 加载数据 with open('players_elo.json', 'r', encoding='utf-8') as f: loaded_data = json.load(f) # 把每个字典转回PlayerElo对象 loaded_players = {k: PlayerElo.from_dict(v) for k, v in loaded_data.items()} # 验证 print(loaded_players[2].initialrating) # 输出1500
小提示
- 不管用哪种方法,都要确保
PlayerElo的所有属性都是JSON可序列化的(比如你的eloratings和elomatches是字典,里面的键值都是int,没问题);如果以后加了其他自定义对象属性,也要同步处理它们的序列化。 indent=4是为了让生成的JSON文件更易读,实际部署可以去掉节省空间。
内容的提问来源于stack exchange,提问作者user3497492
相关产品推荐
相关产品推荐

