Python中如何序列化嵌套在对象实例内的对象实例列表为JSON格式
Python嵌套自定义类JSON序列化解决方案
问题原因
- Python标准库
json模块默认仅支持序列化字符串、数字、列表、字典、布尔值等原生类型,无法直接序列化自定义类实例 - 直接访问实例
__dict__仅能获取当前类的第一层属性,其中嵌套的Fridge实例列表仍然属于不可直接序列化的自定义类型 - 先单独序列化单个
Restaurant再塞入列表的写法会导致最终JSON结构出现字符串嵌套,不符合预期格式
解决方案
给两个自定义类分别封装to_dict实例方法,递归将自身属性转为可序列化的原生字典结构,完全匹配你预期的输出格式。如果你熟悉JS的话,这个to_dict方法的作用和JS中类的toJSON方法类似,区别是Python的json模块不会自动调用这个方法,需要你手动执行转换。
1. 改造类定义
class Restaurant: def __init__(self, owner, password): self.__password = password self.owner = owner self.__owned_fridges = [] # list of owned fridges def add_fridge(self): nickname = input("What would you like to name the fridge: ") # 注意如果之前定义了fr为Fridge的别名可以保留,否则直接用Fridge类名 self.__owned_fridges.append(Fridge(self.owner, nickname)) print("Fridge added!") # 新增序列化方法 def to_dict(self): return { "restaurant": { "name": self.owner, "pw": self.__password, "fridges": [fridge.to_dict() for fridge in self.__owned_fridges] } } # 可选:反序列化方法,应用重启读取数据时转回可调用方法的实例 @classmethod def from_dict(cls, data): rest_data = data["restaurant"] instance = cls(rest_data["name"], rest_data["pw"]) instance._Restaurant__owned_fridges = [Fridge.from_dict(f) for f in rest_data["fridges"]] return instance class Fridge: def __init__(self, owner, nickname): self.nickname = nickname self.owner = owner self.__authorized_users = [owner] self.__contents = [] def add_to_fridge(self): if len(self.__contents) == 5: print("Your fridge is full!") else: item = input("What would you like to add : ") self.__contents.append(item) # 新增序列化方法 def to_dict(self): return { "fridge": { "owner": self.owner, "nickname": self.nickname, "contents": self.__contents } } # 可选:反序列化方法 @classmethod def from_dict(cls, data): fridge_data = data["fridge"] instance = cls(fridge_data["owner"], fridge_data["nickname"]) instance._Fridge__contents = fridge_data["contents"] instance._Fridge__authorized_users = [fridge_data["owner"]] return instance
2. 改造序列化测试代码
不要单独序列化单个实例,先把所有实例转为原生字典结构后,一次性序列化整个data对象:
import json data = { 'restaurants': [] } # 测试代码,注意如果之前定义了res为Restaurant的别名可以保留,否则直接用Restaurant类名 test = Restaurant("Jac", "350b534") test.add_fridge() test.add_fridge() # 先转成字典再加入列表 data['restaurants'].append(test.to_dict()) # 一次性序列化整个数据结构写入文件 with open("restaurant_data.json", "w", encoding="utf-8") as f: json.dump(data, f, indent=4, ensure_ascii=False)
3. 应用重启读取数据(可选)
with open("restaurant_data.json", "r", encoding="utf-8") as f: loaded_data = json.load(f) # 转回可直接调用add_fridge、add_to_fridge等方法的Restaurant实例列表 restaurant_list = [Restaurant.from_dict(item) for item in loaded_data["restaurants"]]
额外说明
Python中双下划线开头的属性会触发名称修饰,类外部访问时需要写成_类名__属性名的格式,类内部可以直接用self.__属性名访问,上述封装的方法已经处理了私有属性的读写问题。
内容的提问来源于stack exchange,提问作者Julius Robinson
相关产品推荐
相关产品推荐

