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

时间:2010-06-18 21:35:08

标签: python import pickle

我有一个pickle转储,它有一个foo.Bar()对象数组。我试图取消它,但Bar()类定义在同一个文件中试图取消,而不是在foo模块中。所以,泡菜抱怨它找不到模块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()

哪个有效,但在我尝试添加之后:

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

我收到了友好的错误:

Traceback (most recent call last):
  File "pyppd.py", line 69, in 
    ppds = loads(ppds_decompressed)
  File "/usr/lib/python2.6/pickle.py", line 1374, in loads
    return Unpickler(file).load()
  File "/usr/lib/python2.6/pickle.py", line 858, in load
    dispatch[key](self)
  File "/usr/lib/python2.6/pickle.py", line 1069, in load_inst
    klass = self.find_class(module, name)
  File "/usr/lib/python2.6/pickle.py", line 1124, in find_class
    __import__(module)
  File "/tmp/test.py", line 69, in 
    p = pickle.load(open("my-pickle.pkl"))
  File "/usr/lib/python2.6/pickle.py", line 1374, in loads
    return Unpickler(file).load()
  File "/usr/lib/python2.6/pickle.py", line 858, in load
    dispatch[key](self)
  File "/usr/lib/python2.6/pickle.py", line 1069, in load_inst
    klass = self.find_class(module, name)
  File "/usr/lib/python2.6/pickle.py", line 1124, in find_class
    __import__(module)
ImportError: No module named foo

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

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()

CAVEAT CAVEAT CAVEAT: 如果您从另一个模块调用此代码段,请说baz,那么未打开的对象将是baz.Bar类型,而不是foo.Bar。假设foo.Barbaz.Bar的类定义相同,那么您将毫无困难地进行解开。但要注意下游使用isinstancetype等。一般来说,尝试为一次性而做任何事情都可能不聪明,因为你的代码库现在包含两个实例Bar。如果可能的话,你应该把foo放在你的路径中。