pickle加载序列化对象后类属性实例值丢失的原因解析
Pickle序列化后predict返回None的核心原因解析
场景与代码说明
假设存在四个文件:main_class.py、help_class.py、train.py和predict.py,代码分别如下:
main_class.py
from help_class import HC class MC: hc = HC() def fit(self): self.hc.fit() def predict(self): return self.hc.predict()
help_class.py
class HC: instances = None def fit(self): self.instances = "fitted" def predict(self): return self.instances
train.py
# train.py from main_class import MC import pickle mc = MC() mc.predict() # 返回 None mc.fit() mc.predict() # 返回 "fitted" with open("./mc_fitted.pkl","wb") as f: pickle.dump(mc,f)
predict.py
# predict.py import pickle with open("./mc_fitted.pkl","rb") as f: mc = pickle.load(f) mc.predict() # 返回 None,不符合预期
核心原因解析
- Pickle的序列化范围限制:Pickle只序列化对象的实例属性,以及重建对象所需的类元信息(类名、所属模块),类级别的属性不会被写入序列化文件。
- MC类中
hc的属性性质:MC里的hc = HC()是类属性,属于MC类本身,不是某个MC实例独有的。在train.py中调用mc.fit()时,实际修改的是这个类属性对应的HC实例的取值,但这个类属性本身不会被Pickle序列化。 - 反序列化的重建逻辑:在
predict.py加载pickle文件时,Python会先导入MC类(此时MC类的类属性hc会被重新初始化,生成一个全新的HC实例,其instances是类属性默认的None),然后基于序列化时保存的MC实例属性(这里MC实例没有自定义实例属性,所以只是一个空的MC实例)完成重建。此时mc.hc指向的是新创建的HC实例,而非train.py中被修改过的那个。 - HC类中
instances的属性覆盖细节:HC类的instances原本是类属性,但self.instances = "fitted"会给HC实例创建一个同名的实例属性,临时覆盖类属性的取值。但由于MC的hc是类属性未被序列化,反序列化后新的HC实例没有这个实例属性,调用predict()时会读取HC类的instances类属性,返回None。
内容的提问来源于stack exchange,提问作者CutePoison
相关产品推荐
相关产品推荐

