为何自定义Pickle类加载时出现AttributeError: Can't get attribute 'MyClass'?
Pickle加载自定义类报错:AttributeError: Can't get attribute 'MyClass' 原因与修复
问题根源
Pickle不会序列化整个类的代码,它只存储对象的实例数据,以及对类的引用信息(类名、类所在的模块路径)。反序列化时,Python需要在当前环境中找到完全匹配的类定义——类名、模块结构、类的属性和方法必须完全一致。
你在另一台电脑的加载代码中完全没有定义MyClass,Python找不到这个类的引用,因此抛出AttributeError。
修复方法
方法1:在加载环境中提供一致的类定义
在加载pickle文件的脚本里,添加和生成端完全相同的MyClass定义;或者把MyClass封装成可导入的模块,两台电脑都安装该模块,加载时导入这个类。
修改后的加载代码示例:
import base64 import pickle # 必须添加和生成端完全一致的类定义 class MyClass: def add_one(self, x): return x + 1 with open("some_location.txt", "rb") as f: encoded_data = f.read() pickled_data = base64.b64decode(encoded_data) loaded = pickle.loads(pickled_data) result = loaded.add_one(5) print(result) # 正常输出6
如果封装成模块(比如创建my_module.py):
# my_module.py class MyClass: def add_one(self, x): return x + 1
生成端导入该类:
import base64 import pickle from my_module import MyClass obj = MyClass() # 后续序列化代码不变
加载端同样导入:
import base64 import pickle from my_module import MyClass # 后续加载代码不变
方法2:使用支持序列化类定义的工具
如果不想在加载端维护类定义,可以用dill库(pickle的扩展),它能序列化类的完整定义,不需要加载端提前定义类。
安装dill:
pip install dill
修改生成代码:
import base64 import dill class MyClass: def add_one(self, x): return x + 1 obj = MyClass() pickled_data = dill.dumps(obj) encoded_data = base64.b64encode(pickled_data) with open("some_location.txt", "wb") as f: f.write(encoded_data)
加载代码:
import base64 import dill with open("some_location.txt", "rb") as f: encoded_data = f.read() pickled_data = base64.b64decode(encoded_data) loaded = dill.loads(pickled_data) result = loaded.add_one(5) print(result)
注意:这种方式会把类代码序列化到文件中,跨不可信环境使用可能存在安全风险。
为什么Scikit-learn模型可以正常加载?
Scikit-learn的模型类(比如svm.SVC)属于官方维护的标准库模块,两台电脑都安装scikit-learn后,加载时Python可以从sklearn.svm模块中找到对应的类定义,满足pickle反序列化对类引用的要求。
另外,Scikit-learn内部对模型的序列化做了优化,确保模型的状态和类引用能在不同环境中(只要库版本一致)正确恢复,而你的自定义类没有这种环境保障,必须手动维护类定义的一致性。
内容的提问来源于stack exchange,提问作者mitchellang
相关产品推荐
相关产品推荐

