从不同模块反序列化Python对象:解决BigModule找不到问题
问题与解决方案:读取其他模块生成的自定义类Pickle文件
问题详情
- 场景:用小型模块
smallModule读取大型模块BigModule生成的pickle文件,其中scikit-learn模型文件可正常读取,但继承自sklearn.base的自定义类对象反序列化失败 - 首次错误:
打开pickle文件可见顶部明文记录:ModuleNotFoundError: No module named 'BigModule'BigModule.submoduleA.submoduleB.submoduleC.submoduleD MyClass - 尝试修改pickle内的模块路径为
smallModule.utils.mypythonfile后,出现新错误:_pickle.UnpicklingError: invalid load key, '\xe2' - 限制:
smallModule需独立运行,无法导入BigModule或修改系统PATH - 疑问:为什么用
pickle.dump(self._classifier, open(filename, 'wb'))保存的sklearn模型不含BigModule引用?如何让自定义类也以类似方式存储?
解决方案
在smallModule项目根目录创建与BigModule完全一致的空目录层级,将自定义类放在对应路径的文件中并正确导入,即可成功反序列化。
最终目录结构
smallModule/ ├── BigModule │ ├── __init__.py │ └── processing │ ├── stuff │ │ ├── script.py │ │ ├── __init__.py │ ├── __init__.py ├── data/ ├── main.py └── utils ├── new_script.py ├── __init__.py
代码修改
- 在
utils/new_script.py中添加导入语句:
from BigModule.processing.stuff.script import MyClass
- 在
main.py中添加:
import BigModule
原因解释
sklearn模型可正常读取的原因:
sklearn的内置模型类在序列化时,pickle记录的是它们自身所属的sklearn官方模块路径(如sklearn.ensemble.RandomForestClassifier),而非保存它们的BigModule路径。只要smallModule环境中安装了scikit-learn,就能找到对应的类,因此可以正常反序列化。直接修改pickle文件报错的原因:
pickle是二进制序列化格式,仅开头的类路径是明文,后续都是结构化的二进制数据。手动修改明文部分会破坏整个文件的二进制结构,导致反序列化时出现无效加载键的错误。镜像目录结构可行的原因:
pickle反序列化时,会根据保存的类全路径(BigModule.submoduleA...MyClass)在Python的模块搜索路径中查找类。在smallModule根目录创建和BigModule一致的目录结构后,Python会将当前项目根目录纳入模块搜索路径,从而找到对应路径下的MyClass,无需依赖原始的BigModule。
内容的提问来源于stack exchange,提问作者noe-miro
相关产品推荐
相关产品推荐

