You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 16:15:51