如何保存以自定义对象为键的字典?json与pickle保存报错
自定义对象作为字典键的序列化问题
核心结论
- JSON:必须将自定义对象转换为JSON支持的基础类型(str、int、float等)才能作为字典键,JSON规范不允许复杂对象作为键。
- Pickle:支持自定义对象作为字典键,但需要你的类实现
__hash__和__eq__方法,确保对象可哈希且能正确比较。
为什么JSON保存会报错?
从报错信息可以明确看到:TypeError: keys must be str, int, float, bool or None, not my_node,JSON编码器只允许基础类型作为字典键,自定义对象不在允许范围内。
JSON解决方案:转换键为基础类型
方案1:用对象的属性作为键
直接提取自定义对象的唯一标识属性(比如name)作为字典键:
import json class my_node(object): def __init__(self, name): self.name=name node=my_node(1) # 使用对象的name属性作为字典键 my_dict={node.name: 1} print(my_dict) # 保存JSON with open('test.json', "w") as outfile: json.dump(my_dict, outfile) # 读取验证 with open('test.json', "r") as infile: loaded = json.load(infile) print(loaded[node.name]) # 输出1
方案2:将对象序列化为字符串作为键
如果需要保留对象的完整信息,可以先把对象转成JSON字符串,再作为键:
import json class my_node(object): def __init__(self, name): self.name=name node=my_node(1) # 将对象转为JSON字符串作为键 node_key = json.dumps({"name": node.name}) my_dict={node_key: 1} # 保存JSON with open('test.json', "w") as outfile: json.dump(my_dict, outfile) # 读取并还原对象 with open('test.json', "r") as infile: loaded_dict = json.load(infile) # 解析键还原对象 node_info = json.loads(next(iter(loaded_dict.keys()))) new_node = my_node(node_info["name"]) print(loaded_dict[node_key]) # 输出1
Pickle的处理方式
Pickle支持将自定义对象作为字典键,但要求类实现__hash__和__eq__方法——这是字典键的基本要求(可哈希、可比较),否则序列化后读取时无法正确匹配键。
Pickle示例代码
import pickle class my_node(object): def __init__(self, name): self.name=name # 基于name属性实现哈希 def __hash__(self): return hash(self.name) # 基于name属性实现相等判断 def __eq__(self, other): if isinstance(other, my_node): return self.name == other.name return False node=my_node(1) my_dict={node: 1} print(my_dict) # 用Pickle保存 with open('test.pkl', "wb") as outfile: pickle.dump(my_dict, outfile) # 读取验证 with open('test.pkl', "rb") as infile: loaded_dict = pickle.load(infile) print(loaded_dict) # 输出{<__main__.my_node object at 0x...>: 1} # 用新创建的同属性对象获取值 new_node = my_node(1) print(loaded_dict[new_node]) # 输出1
内容的提问来源于stack exchange,提问作者Mihai.Mehe
相关产品推荐
相关产品推荐

