np.ndarray
用来__reduce__
腌制自己。当您调用该函数以了解发生了什么时,我们可以看看它实际返回的内容:
>>> obj = RealisticInfoArray([1, 2, 3], info='foo')
>>> obj.__reduce__()
(<built-in function _reconstruct>, (<class 'pick.RealisticInfoArray'>, (0,), 'b'), (1, (3,), dtype('int64'), False, '\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'))
所以,我们得到了一个三元组。__reduce__
描述每个元素在做什么的文档:
返回元组时,它的长度必须在 2 到 5 个元素之间。可选元素可以省略,也可以提供 None 作为它们的值。这个元组的内容被正常腌制,并用于在解腌时重建对象。每个元素的语义是:
将被调用以创建对象的初始版本的可调用对象。元组的下一个元素将为这个可调用对象提供参数,后面的元素提供额外的状态信息,这些信息随后将用于完全重建腌制数据。
在 unpickling 环境中,该对象必须是一个类,一个注册为“安全构造函数”(见下文)的可调用对象,或者它必须具有一个__safe_for_unpickling__
具有真值的属性。否则,UnpicklingError
将在 unpickling 环境中引发 an 。请注意,像往常一样,可调用对象本身是按名称腌制的。
可调用对象的参数元组。
可选地,对象的状态,将被传递给对象的
__setstate__()
方法,如 Pickling 和 unpickling 普通类实例部分所述。如果对象没有__setstate__()
方法,那么和上面一样,该值必须是一个字典,它将被添加到对象的__dict__
.
所以,_reconstruct
是调用来重建对象的函数,(<class 'pick.RealisticInfoArray'>, (0,), 'b')
是传递给该函数的参数,(1, (3,), dtype('int64'), False, '\x01\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00'))
并被传递给类' __setstate__
。这给了我们一个机会;我们可以覆盖__reduce__
并提供我们自己的元组到__setstate__
,然后另外覆盖__setstate__
,以在我们取消腌制时设置我们的自定义属性。我们只需要确保我们保留了父类需要的所有数据,并且也调用了父类__setstate__
:
class RealisticInfoArray(np.ndarray):
def __new__(cls, input_array, info=None):
obj = np.asarray(input_array).view(cls)
obj.info = info
return obj
def __array_finalize__(self, obj):
if obj is None: return
self.info = getattr(obj, 'info', None)
def __reduce__(self):
# Get the parent's __reduce__ tuple
pickled_state = super(RealisticInfoArray, self).__reduce__()
# Create our own tuple to pass to __setstate__
new_state = pickled_state[2] + (self.info,)
# Return a tuple that replaces the parent's __setstate__ tuple with our own
return (pickled_state[0], pickled_state[1], new_state)
def __setstate__(self, state):
self.info = state[-1] # Set the info attribute
# Call the parent's __setstate__ with the other tuple elements.
super(RealisticInfoArray, self).__setstate__(state[0:-1])
用法:
>>> obj = pick.RealisticInfoArray([1, 2, 3], info='foo')
>>> pickle_str = pickle.dumps(obj)
>>> pickle_str
"cnumpy.core.multiarray\n_reconstruct\np0\n(cpick\nRealisticInfoArray\np1\n(I0\ntp2\nS'b'\np3\ntp4\nRp5\n(I1\n(I3\ntp6\ncnumpy\ndtype\np7\n(S'i8'\np8\nI0\nI1\ntp9\nRp10\n(I3\nS'<'\np11\nNNNI-1\nI-1\nI0\ntp12\nbI00\nS'\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\np13\nS'foo'\np14\ntp15\nb."
>>> new_obj = pickle.loads(pickle_str)
>>> new_obj.info
'foo'