如何在Python中索引动态生成的嵌套对象?类实例访问问题求助
训练计划GUI开发问题与解决方案
相关代码
import tkinter as tk import tksheet import json import pickle class Treino(object): class config(object): _list = [] def __init__(self, name, value): self.name = name self.value = value self._list.append(self) class CategoriaTreino(object): _list = [] def __init__(self, name): self.name = name self._list.append(self) self.config = {'RNG': 0} class SubCategoriaTreino(object): _list = [] def __init__(self, name, repet): self.name = name self.repetição = repet self._list.append(self) pass def returnCat(): for cat in TreinoMain.CategoriaTreino._list: yield cat def returnSubCat(): for subcat in TreinoMain.CategoriaTreino.SubCategoriaTreino._list: yield subcat def savefile(): with open('treinos.pkl', 'wb') as file: for cat in returnCat(): pickle.dump(cat, file, pickle.HIGHEST_PROTOCOL) def loadfile(): data = [] with open('treinos.pkl', 'wb') as file: # 注意:此处原代码模式错误,应为'rb' while True: try: data.append(pickle.load(file)) except EOFError: break for d in data: #iterate through objs pass if __name__ == "__main__": TreinoMain = Treino() ca1 = TreinoMain.CategoriaTreino("Braço") subca1 = ca1.SubCategoriaTreino('Biceps', '2x10')
问题描述
我正在开发一款支持用户动态增删分类与子分类的GUI,用于随机生成训练计划,因此采用嵌套类而非嵌套数据类型实现。目前遇到两个问题:
- 创建父对象实例(如
ca1)和子对象实例(如subca1)后,无法通过ca1.subca1.name的方式访问子对象属性; - 担心使用pickle加载对象后,类中的
_list列表会失效。
希望能实现父实例对子实例的便捷访问,或者得到动态生成嵌套对象的更优方案。
解决方案
问题1:父实例便捷访问子实例
当前代码中,SubCategoriaTreino实例仅被添加到类的_list,未与父CategoriaTreino实例绑定,因此无法通过父实例直接访问。可按以下方式修改:
方式1:父类维护子实例列表与映射表
修改CategoriaTreino和SubCategoriaTreino的实现,让父实例持有子实例的引用:
class Treino(object): class CategoriaTreino(object): _list = [] def __init__(self, name): self.name = name self._list.append(self) self.config = {'RNG': 0} # 新增:存储当前分类下的子分类 self.subcategorias = [] # 新增:按名称快速查找子分类的字典 self.subcat_map = {} class SubCategoriaTreino(object): _list = [] def __init__(self, parent_cat, name, repet): self.parent = parent_cat # 绑定父分类实例 self.name = name self.repetição = repet self._list.append(self) # 将自己添加到父分类的容器中 parent_cat.subcategorias.append(self) parent_cat.subcat_map[name] = self # 创建实例时传入父分类 if __name__ == "__main__": TreinoMain = Treino() ca1 = TreinoMain.CategoriaTreino("Braço") subca1 = TreinoMain.CategoriaTreino.SubCategoriaTreino(ca1, 'Biceps', '2x10') # 访问子分类的两种方式 print(ca1.subcat_map['Biceps'].name) # 输出 Biceps for subcat in ca1.subcategorias: print(subcat.repetição) # 输出 2x10
方式2:动态绑定子实例为父实例属性
如果需要ca1.biceps这种直接属性访问,可在SubCategoriaTreino的__init__中添加:
# 以子分类名称作为属性名(建议转小写避免冲突) setattr(parent_cat, name.lower(), self) # 之后可直接通过 ca1.biceps.name 访问
问题2:pickle加载后类_list失效
pickle仅序列化实例对象,不会保存类变量状态。加载时需手动将实例添加到类的_list中,同时修正原代码的文件打开模式错误:
def loadfile(): data = [] # 修正:读取文件需用'rb'模式,原代码的'wb'会清空文件 with open('treinos.pkl', 'rb') as file: while True: try: obj = pickle.load(file) data.append(obj) # 根据实例类型,添加到对应类的_list中 if isinstance(obj, Treino.CategoriaTreino): if obj not in Treino.CategoriaTreino._list: Treino.CategoriaTreino._list.append(obj) # 同步子分类到对应的_list for subcat in obj.subcategorias: if subcat not in Treino.CategoriaTreino.SubCategoriaTreino._list: Treino.CategoriaTreino.SubCategoriaTreino._list.append(subcat) elif isinstance(obj, Treino.CategoriaTreino.SubCategoriaTreino): if obj not in Treino.CategoriaTreino.SubCategoriaTreino._list: Treino.CategoriaTreino.SubCategoriaTreino._list.append(obj) except EOFError: break
更优实现方案:采用组合模式替代嵌套类
嵌套类会增加结构复杂度,推荐用组合模式设计独立类,通过实例引用建立层级关系:
import pickle # 子分类类 class SubCategoriaTreino: _all_subcats = [] # 存储所有子分类实例 def __init__(self, name, repet): self.name = name self.repetição = repet self._all_subcats.append(self) # 分类类 class CategoriaTreino: _all_cats = [] # 存储所有分类实例 def __init__(self, name): self.name = name self.config = {'RNG': 0} self.subcategorias = [] # 当前分类下的子分类 self.subcat_map = {} self._all_cats.append(self) def add_subcat(self, name, repet): subcat = SubCategoriaTreino(name, repet) self.subcategorias.append(subcat) self.subcat_map[name] = subcat return subcat # 训练计划主类 class Treino: def __init__(self): self.categorias = CategoriaTreino._all_cats self.subcategorias = SubCategoriaTreino._all_subcats # 保存与加载函数 def savefile(): with open('treinos.pkl', 'wb') as f: # 保存所有分类(子分类会随引用自动序列化) pickle.dump(CategoriaTreino._all_cats, f, pickle.HIGHEST_PROTOCOL) def loadfile(): with open('treinos.pkl', 'rb') as f: loaded_cats = pickle.load(f) # 更新类的实例列表 CategoriaTreino._all_cats.clear() CategoriaTreino._all_cats.extend(loaded_cats) # 重新收集所有子分类 SubCategoriaTreino._all_subcats.clear() for cat in loaded_cats: SubCategoriaTreino._all_subcats.extend(cat.subcategorias) return Treino() # 使用示例 if __name__ == "__main__": treino = Treino() braco_cat = CategoriaTreino("Braço") biceps_subcat = braco_cat.add_subcat('Biceps', '2x10') # 访问子分类 print(braco_cat.subcat_map['Biceps'].repetição) # 输出 2x10 # 保存与加载 savefile() loaded_treino = loadfile()
这种结构层级清晰,增删操作更易实现,序列化逻辑也更简洁。
内容的提问来源于stack exchange,提问作者vdevit
相关产品推荐
相关产品推荐

