如何在JSON序列化/反序列化后保留Python对象的引用链接
如何让JSON序列化保留Python对象的引用关联?
JSON本身不支持对象引用的原生表达,默认序列化会将每个对象引用转化为独立的JSON结构,导致反序列化后原有的引用关联丢失。要解决这个问题,有两种常用实现思路:
方法一:使用支持引用保留的序列化库(如jsonpickle)
jsonpickle是专为Python设计的序列化库,能自动处理对象引用——序列化时为每个唯一对象生成标识符,反序列化时自动重建引用关联。
修改后的测试代码
import jsonpickle import CompositeStandard as cs # 测试逻辑 obj = cs.CompositeDB() obj.allComposite = [cs.Ply(defects=[cs.Wrinkle()])] obj.allDefects = [obj.allComposite[0].defects[0]] # 引用同一个对象 obj.allDefects[0].area = 678 # 修改同步到两个引用 print(obj) print("\n\n") # 序列化,开启引用支持 json_str = jsonpickle.encode(obj, unpicklable=True) # 保存到文件 with open('D:\\CAD_library_sampling\\CompoST_examples\\test_sd.json', 'w') as out_file: out_file.write(json_str) # 读取并反序列化 with open('D:\\CAD_library_sampling\\CompoST_examples\\test_sd.json', "r") as in_file: json_str = in_file.read() D = jsonpickle.decode(json_str) D.allDefects[0].area = 99999 # 修改同步到两个引用 print("\n\n\n") print(D.allDefects[0]) print("\n\n\n") print(D.allComposite[0].defects[0]) # 现在会打印"area=99999"
方法二:自定义序列化逻辑,手动管理对象引用
如果需要完全控制JSON格式,可以给需要被引用的对象添加唯一标识符,序列化时记录对象ID,反序列化时先创建所有对象,再根据ID重建引用关系。
步骤1:给需要引用的类添加唯一ID属性
修改CompositeStandard中的类示例:
import uuid class Wrinkle: def __init__(self): self._id = str(uuid.uuid4()) self.area = 0 # 同理给Ply、CompositeDB等类按需添加_id属性
步骤2:自定义序列化与反序列化函数
import json def serialize_with_ref(obj): # 用字典记录所有对象的ID和数据 obj_map = {} # 递归遍历对象,收集所有带_id的对象 def traverse(item): if hasattr(item, "_id") and item._id not in obj_map: obj_dict = item.__dict__.copy() obj_map[item._id] = obj_dict # 遍历属性,将嵌套对象替换为引用标记 for key, value in obj_dict.items(): if isinstance(value, list): for idx, elem in enumerate(value): if hasattr(elem, "_id"): value[idx] = {"$ref": elem._id} else: traverse(elem) elif hasattr(value, "_id"): obj_dict[key] = {"$ref": value._id} else: traverse(value) elif isinstance(item, list): for elem in item: traverse(elem) elif isinstance(item, dict): for value in item.values(): traverse(value) traverse(obj) # 保存根对象ID和所有对象映射 return json.dumps({ "root_id": obj._id, "objects": obj_map }) def deserialize_with_ref(json_str): data = json.loads(json_str) obj_map = {} # 先创建所有对象实例 for obj_id, obj_dict in data["objects"].items(): # 根据类特征创建实例,需根据你的实际类结构调整 if "defects" in obj_dict: obj = cs.Ply() elif "area" in obj_dict: obj = cs.Wrinkle() else: obj = cs.CompositeDB() obj.__dict__.update(obj_dict) obj_map[obj_id] = obj # 重建引用关系 def resolve_refs(item): if isinstance(item, list): for idx, elem in enumerate(item): if isinstance(elem, dict) and "$ref" in elem: item[idx] = obj_map[elem["$ref"]] else: resolve_refs(elem) elif isinstance(item, dict): for key, value in item.items(): if isinstance(value, dict) and "$ref" in value: item[key] = obj_map[value["$ref"]] else: resolve_refs(value) elif hasattr(item, "__dict__"): for key, value in item.__dict__.items(): if isinstance(value, dict) and "$ref" in value: setattr(item, key, obj_map[value["$ref"]]) else: resolve_refs(value) root_obj = obj_map[data["root_id"]] resolve_refs(root_obj) return root_obj
使用自定义函数的测试代码
import CompositeStandard as cs import uuid # 测试逻辑 obj = cs.CompositeDB() obj._id = str(uuid.uuid4()) obj.allComposite = [cs.Ply(defects=[cs.Wrinkle()])] obj.allDefects = [obj.allComposite[0].defects[0]] obj.allDefects[0].area = 678 print(obj) print("\n\n") # 序列化 json_str = serialize_with_ref(obj) # 保存到文件 with open('D:\\CAD_library_sampling\\CompoST_examples\\test_sd.json', 'w') as out_file: out_file.write(json_str) # 读取并反序列化 with open('D:\\CAD_library_sampling\\CompoST_examples\\test_sd.json', "r") as in_file: json_str = in_file.read() D = deserialize_with_ref(json_str) D.allDefects[0].area = 99999 print("\n\n\n") print(D.allDefects[0]) print("\n\n\n") print(D.allComposite[0].defects[0]) # 会打印"area=99999"
内容的提问来源于stack exchange,提问作者LuTze
相关产品推荐
相关产品推荐

