Python如何存储包含PySide2控件的自定义类对象数组?
问题根本原因
序列化失败本质是 PySide2的UI控件对象(QFrame、QLabel、centralwidget等)都绑定了运行时的窗口上下文、底层C++对象句柄,属于不可序列化的对象,不管是json还是pickle都无法直接持久化这类对象,就算强行存储成功,下次程序重启后读取的控件句柄也是无效的,无法正常使用。
可行实现方案
可以通过重写person类的__getstate__和__setstate__魔术方法,自定义序列化/反序列化规则:序列化时只保存纯数据属性,反序列化时根据保存的数据重新生成对应的UI控件,是成本最低的实现方式。
如果你一定要用json序列化,原理和下述方案一致,需要额外自定义JSONEncoder和Decoder把person实例转成字典再序列化,实现起来比pickle繁琐,无特殊需求优先用pickle方案即可。
步骤1:修改person类的序列化逻辑
示例代码如下:
import pickle from PySide2.QtWidgets import QFrame, QLabel # 注意你原代码里的类名是pesrson,属于拼写错误,可自行调整为正确的person class person: def __init__(self, name, centralwidget=None): self.name = name self.centralwidget = centralwidget # 运行时才有效的UI控件,不需要序列化 self.ui_elements = None # 存储config生成的UI元素,也不需要序列化 def config(self): # 保留你原来生成QFrame、QLabel的原有逻辑 frame = QFrame(self.centralwidget) label = QLabel(self.name, frame) self.ui_elements = (frame, label) return frame # 自定义pickle序列化时需要持久化的内容 def __getstate__(self): # 只返回纯数据属性,排除所有UI类对象 return { "name": self.name # 其他需要持久化的自定义纯数据属性都可以添加到这里 } # 自定义pickle反序列化时的实例重建逻辑 def __setstate__(self, state): # 先恢复所有数据属性 self.__dict__.update(state) # UI相关属性先置空,等读取后手动传入当前运行时的centralwidget再生成UI self.centralwidget = None self.ui_elements = None
步骤2:序列化存储实例数组
你原代码中的self.tree是person实例数组,直接序列化即可:
# 存储到本地文件 with open("person_data.pkl", "wb") as f: pickle.dump(self.tree, f)
步骤3:反序列化读取并恢复UI
读取后需要手动给每个实例传入当前运行时的centralwidget,再调用config方法生成UI即可正常使用所有属性:
# 从本地文件读取 with open("person_data.pkl", "rb") as f: loaded_tree = pickle.load(f) # 恢复UI逻辑,读取后添加到当前布局中 for p in loaded_tree: p.centralwidget = self.ui.centralwidget # 传入当前运行时的中控件 p_frame = p.config() # 重新生成UI元素 self.ui.verticalLayout.addWidget(p_frame) self.tree = loaded_tree
注意事项
- 不要尝试序列化任何Qt UI控件,所有UI元素都应该在反序列化后基于保存的纯数据在当前运行时重新生成
- 如果你的person类还有其他自定义的纯数据属性,全部放到
__getstate__的返回字典里即可完成持久化
内容的提问来源于stack exchange,提问作者Faezeh Farajzade
相关产品推荐
相关产品推荐

