在使用自定义 pickler 将 Django HttpResponse 对象序列化后,在反序列化的过程中遇到了 UnpicklingError: NEWOBJ class argument isn't a type object 错误。
解决方案
Pickle 的序列化和反序列化过程涉及两个步骤:序列化和反序列化。序列化是将对象转换为可存储或传输的格式,反序列化是从存储或传输的格式中重新创建对象。在自定义 pickler 中,允许将一些无法正常序列化的对象(例如套接字或文件)替换为它们的字符串表示形式。
在尝试反序列化 Django HttpResponse 对象时,遇到了 UnpicklingError: NEWOBJ class argument isn't a type object 错误。
错误原因
在使用自定义 pickler 将对象序列化时,对象的类型信息也会被序列化。在反序列化时,需要使用相同的类型信息来重新创建对象。但是,在自定义 pickler 中,将一些无法正常序列化的对象替换为它们的字符串表示形式,导致反序列化时无法找到相应的类型信息,从而引发了错误。
解决方法
为了解决此问题,需要将自定义 pickler 修改为在序列化时保留对象的类型信息。可以使用 pickle.Pickler 的 persistent_id 属性来实现,该属性允许在序列化时指定对象的替代ID。
以下是修改后的代码:
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 type(obj), 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 isinstance(obj_id, tuple):
obj_type, obj_value = obj_id
return obj_type(obj_value)
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()
在修改后的代码中,在 persistent_id 方法中,如果遇到无法正常序列化的对象,则会使用 pickle.Pickler 的 persistent_id 属性来指定对象的替代ID。这个替代ID是一个元组,第一个元素是对象的类型,第二个元素是对象的字符串表示形式。
在反序列化时,如果遇到带有替代ID的对象,则会使用 persistent_load 方法来重新创建对象。在 persistent_load 方法中,会根据对象的类型和字符串表示形式来重新创建对象。
这样,就可以解决反序列化时遇到的 UnpicklingError: NEWOBJ class argument isn't a type object 错误。