Как заменить module.Class () на локально определенный Class () при загрузке с помощью Python's Pickle? - PullRequest
0 голосов
/ 19 июня 2010

У меня есть дамп pickle, в котором есть массив объектов foo.Bar ().Я пытаюсь распаковать его, но определение класса Bar () находится в том же файле, который пытается распаковать, а не в модуле 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()

Что работает, но когда я пытаюсьдобавить, после этого:

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 Ответ

3 голосов
/ 19 июня 2010
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.Bar и baz.Bar одинаковы, у вас не возникнет проблем с отбором. Но будьте осторожны с последующим использованием isinstance, type и т. Д. В общем, попытка сделать что-то подобное для чего-то, кроме одноразового использования, вероятно, не является разумной, поскольку ваша кодовая база теперь содержит два экземпляра Bar , Если это вообще возможно, вы должны просто вставить foo в вашу PATH.

...