UnpicklingError:NEWOBJ类参数不是类型对象

时间:2013-07-08 05:38:21

标签: python pickle

我正在使用一个自定义pickler,它根据来自Shane Hathaway的代码替换任何不可拾取的对象(如套接字或文件)及其字符串表示: Python: Pickling a dict with some unpicklable items

它大部分时间都可以工作,但是当我尝试取消Django HttpResponse的解开时,我收到以下错误: UnpicklingError:NEWOBJ类参数不是类型对象

我不知道错误究竟意味着什么。如果泡菜好的话,为什么它不能破坏?我在Google上发现了三个对此错误的引用,但没有真正解释它为何发生或如何修复它。

这是我的代码:

from cPickle import Pickler, Unpickler, UnpicklingError

class FilteredObject:
    def __init__(self, about):
        self.about = about
    def __repr__(self):
        return 'FilteredObject(%s)' % repr(self.about)

class MyPickler(object):
    def __init__(self, file, protocol=2):
        pickler = Pickler(file, protocol)
        pickler.persistent_id = self.persistent_id
        self.dump = pickler.dump
        self.clear_memo = pickler.clear_memo

    def persistent_id(self, obj):
           if not hasattr(obj, '__getstate__') and not isinstance(obj,
        (basestring, bool, int, long, float, complex, tuple, list, set, dict)):
            return ["filtered:%s" % str(obj)]
        else:
            return None

class MyUnpickler(object):
    def __init__(self, file):
        unpickler = Unpickler(file)
        unpickler.persistent_load = self.persistent_load
        self.load = unpickler.load
        self.noload = unpickler.noload

    def persistent_load(self, obj_id):
        if obj_id[0].startswith('filtered:'):
            return FilteredObject(obj_id[0][9:])
        else:
            raise UnpicklingError('Invalid persistent id')

###### serialize to file

f = open('test.txt','wb')
p = MyPickler(f)
p.dump(data)
f.close()

###### unserialize from file

f = open('test.txt','rb')
pickled_data = f.read()
f.seek(0)
u = MyUnpickler(f)
data = u.load()    

1 个答案:

答案 0 :(得分:0)

成功的酸洗分两步进行,Pickler的pickle.dump和Unpickler的pickle.load。 Pickler将对象转换为序列化格式(例如字符串),Unpickler消化pickle对象并生成等同于原始对象的新对象。 Pickle有几个可用于转储泡菜的功能......所以第1部分是将对象转换为序列化格式。使用自定义pickler,您可以绕过python的一些安全措施来挑选pickle本身无法腌制的对象。按照你的例子,我可以创建一个简单的Pickler,通过将每个对象转换为__repr__来将lambda和whatnot转换为字符串。

>>> x = lambda x:x
>>> repr(x)
'<function <lambda> at 0x4d39cf0>'
>>> 
>>> import pickle
>>> l = repr(x)
>>> pickle.dumps(l)
"S'<function <lambda> at 0x4d39cf0>'\np0\n."

这绝对是可以选择的,因为它是一个字符串。但是,问题是如何从保存的字符串构建对象。对于lambda,如果你有一个可以查找内存的函数 在字符串中注明的引用,你可以得到对象...但只有你仍然有 原始物体在你的记忆中存活......所以这不好。因此,只有在__repr__字符串中包含足够的信息才能从存储的字符串信息中构建新对象时,转换为字符串的技巧才有效。您可以更好地了解存储的内容,但最终可能会通过将对象转换为字符串来解决问题。所以这是你的Pickler工作的情况,但你的Unpickler会失败。

字典很有趣,因为它们可以包含任何内容,并且通常很快就能完成。最糟糕的词典之一是globals()词典。为了序列化它,我使用dill,它可以在python中序列化几乎任何东西。

>>> import dill
>>> 
>>> def foo(a):
...   def bar(x):
...     return a*x
...   return bar
... 
>>> class baz(object):
...   def __call__(self, a,x):
...     return foo(a)(x)
... 
>>> b = baz()
>>> b(3,2)
6
>>> c = baz.__call__
>>> c(b,3,2)
6
>>> g = dill.loads(dill.dumps(globals()))
>>> g
{'dill': <module 'dill' from '/Library/Frameworks/Python.framework/Versions/7.2/lib/python2.7/site-packages/dill-0.2a.dev-py2.7.egg/dill/__init__.pyc'>, 'c': <unbound method baz.__call__>, 'b': <__main__.baz object at 0x4d61970>, 'g': {...}, '__builtins__': <module '__builtin__' (built-in)>, 'baz': <class '__main__.baz'>, '_version': '2', '__package__': None, '__name__': '__main__', 'foo': <function foo at 0x4d39d30>, '__doc__': None}

实际上,dill将它的类型注册到pickle注册表中,所以如果你有一些使用pickle的黑盒代码并且你无法真正编辑它,那么只需导入dill就可以神奇地制作它没有monkeypatching第三方代码的工作。

或者,如果您希望将整个解释器会话作为“python图像”发送,dill也可以这样做。

>>> # continuing from above
>>> dill.dump_session('foobar.pkl')
>>>
>>> ^D
dude@sakurai>$ python
Python 2.7.5 (default, Sep 30 2013, 20:15:49) 
[GCC 4.2.1 (Apple Inc. build 5566)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> dill.load_session('foobar.pkl')
>>> c(b,3,2)
6

Dill还有some good tools帮助您了解代码失败时导致酸洗失败的原因。