使用 Python 的 Pickle 加载时,如何将 module.Class() 替换为本地定义的 Class()?

Posted

技术标签:

【中文标题】使用 Python 的 Pickle 加载时,如何将 module.Class() 替换为本地定义的 Class()?【英文标题】:How to substitute module.Class() to locally defined Class() when loading with Python's Pickle? 【发布时间】:2011-03-05 15:09:44 【问题描述】:

我有一个包含 foo.Bar() 对象数组的泡菜转储。我正在尝试取消腌制它,但 Bar() 类定义位于试图取消腌制的同一文件中,而不是在 foo 模块中。所以,pickle 抱怨它找不到模块 foo。

我尝试注入 foo 模块做类似的事情: 导入小鬼,系统

class Bar:
    pass

foo_module = imp.new_module('foo')
foo_module.Bar = Bar
sys.modules['foo'] = foo_module

import foo
print foo.Bar()

哪个有效,但是当我尝试添加时,之后:

import pickle
p = pickle.load(open("my-pickle.pkl"))

我收到友好错误:

回溯(最近一次通话最后): 文件“pyppd.py”,第 69 行,在 ppds = 负载(ppds_decompressed) 文件“/usr/lib/python2.6/pickle.py”,第 1374 行,加载中 返回 Unpickler(file).load() 文件“/usr/lib/python2.6/pickle.py”,第 858 行,加载中 调度[键](自我) 文件“/usr/lib/python2.6/pickle.py”,第 1069 行,在 load_inst klass = self.find_class(模块,名称) 文件“/usr/lib/python2.6/pickle.py”,第 1124 行,在 find_class __import__(模块) 文件“/tmp/test.py”,第 69 行,在 p = pickle.load(open("my-pickle.pkl")) 文件“/usr/lib/python2.6/pickle.py”,第 1374 行,加载中 返回 Unpickler(file).load() 文件“/usr/lib/python2.6/pickle.py”,第 858 行,加载中 调度[键](自我) 文件“/usr/lib/python2.6/pickle.py”,第 1069 行,在 load_inst klass = self.find_class(模块,名称) 文件“/usr/lib/python2.6/pickle.py”,第 1124 行,在 find_class __import__(模块) ImportError:没有名为 foo 的模块

有什么想法吗?

【问题讨论】:

【参考方案1】:
class Bar:
    pass

class MyUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module == "foo" and name == "Bar":
            return Bar
        else:
            return pickle.Unpickler.find_class(self, module, name)

bars = MyUnpickler(open("objects.pkl")).load()

注意事项注意事项: 如果您从另一个模块调用这个 sn-p 代码,比如说 baz,那么未腌制的对象将是 baz.Bar 类型,而不是 foo.Bar。假设foo.Barbaz.Bar 的类定义是一样的,你就可以轻松解压了。但是要小心下游使用isinstancetype 等。一般来说,尝试为任何事情做这种事情而不是一次性的可能并不聪明,因为你的代码库现在包含Bar 的两个实例.如果可能的话,你应该把 foo 放在你的 PATH 中。

【讨论】:

谢谢,这就像一个魅力。无论如何,我会更加努力地考虑是否可以避免这样做...... 更一般地说,您可以编写if module == "foo": return getattr(sys.modules[__name__], name) ,这样相同的代码将适用于同一模块中本地定义的所有类,而不仅仅是Bar

以上是关于使用 Python 的 Pickle 加载时,如何将 module.Class() 替换为本地定义的 Class()?的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:需要一个类似字节的对象,而不是使用 pickle 加载时的“str”

如何在小 GUI 中修复“allow_pickle=False 时无法加载对象数组”

python使用pickle保存和加载机器学模型

使用pickle为我的游戏创建保存/加载功能的问题(Python)

如何更改加载逻辑回归模型的决策阈值

使用 cx_freeze 时如何加载泡菜模型?