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

Vit*_*sta 1 python import pickle

我有一个 pickle 转储,其中包含一系列 foo.Bar() 对象。我试图取消它,但 Bar() 类定义位于尝试取消pickle 的同一个文件中,而不是在 foo 模块中。因此,pickle 抱怨它找不到模块 foo。

我尝试注入 foo 模块,执行类似以下操作: import imp, sys

class Bar:
    pass

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

import foo
print foo.Bar()
Run Code Online (Sandbox Code Playgroud)

这是有效的,但是当我尝试添加之后:

import pickle
p = pickle.load(open("my-pickle.pkl"))
Run Code Online (Sandbox Code Playgroud)

我收到友好错误:

回溯(最近一次调用最后一次):
  文件“pyppd.py”,第 69 行,位于
    ppds = 负载(ppds_解压缩)
  文件“/usr/lib/python2.6/pickle.py”,第 1374 行,加载中
    返回Unpickler(文件).load()
  文件“/usr/lib/python2.6/pickle.py”,第 858 行,加载中
    调度[key](自己)
  文件“/usr/lib/python2.6/pickle.py”,第 1069 行,位于 load_inst
    klass = self.find_class(模块, 名称)
  文件“/usr/lib/python2.6/pickle.py”,第 1124 行,在 find_class 中
    __导入__(模块)
  文件“/tmp/test.py”,第 69 行,位于
    p = pickle.load(open("my-pickle.pkl"))
  文件“/usr/lib/python2.6/pickle.py”,第 1374 行,加载中
    返回Unpickler(文件).load()
  文件“/usr/lib/python2.6/pickle.py”,第 858 行,加载中
    调度[key](自己)
  文件“/usr/lib/python2.6/pickle.py”,第 1069 行,位于 load_inst
    klass = self.find_class(模块, 名称)
  文件“/usr/lib/python2.6/pickle.py”,第 1124 行,在 find_class 中
    __导入__(模块)
导入错误:没有名为 foo 的模块

有任何想法吗?

gil*_*esc 5

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()
Run Code Online (Sandbox Code Playgroud)

警告 警告 警告:如果您从另一个模块调用这段代码,比如说baz,那么 unpickled 对象的类型将是baz.Bar,而不是foo.Barfoo.Bar假设和的类定义baz.Bar相同,那么 unpickle 就没有问题了。但要小心下游使用isinstancetype等。一般来说,尝试为除一次性之外的任何事情执行此类操作可能并不明智,因为您的代码库现在包含两个Bar. 如果可能的话,您应该输入foo您的路径。