np.ndarray
verwendet __reduce__
, um sich selbst zu gießen. Wir können einen Blick darauf werfen, was es gibt tatsächlich, wenn Sie diese Funktion aufrufen, um eine Vorstellung davon zu bekommen, was los ist:
>>> 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'))
Also, wir wieder ein 3-Tupel erhalten. Die Dokumentation für __reduce__
beschreiben, was jedes Element tut:
Wenn ein Tupel zurückgegeben wird, muss es zwischen zwei und fünf Elementen lang sein. Optionale Elemente können entweder weggelassen werden oder Keine kann als Wert bereitgestellt werden. Der Inhalt dieses Tupels wird wie üblich gebeizt und verwendet, um das Objekt zum Zeitpunkt der Entpixelung zu rekonstruieren. Die Semantik jedes Element ist:
Ein aufrufbare Objekt, das die erste Version von das Objekt erstellen aufgerufen wird. Das nächste Element des Tupels liefert Argumente für , die aufrufbar sind, und spätere Elemente liefern zusätzliche Zustandsinformationen , die anschließend verwendet werden, um die gebeizten Daten vollständig zu rekonstruieren.
Im Unpickling Umgebung dieses Objekt muss entweder eine Klasse, ein aufrufbar registriert als „sichere Konstruktor“ (siehe unten), oder es muss hat ein Attribut __safe_for_unpickling__
mit einem wahren Wert. Andernfalls wird ein UnpicklingError
in der unpickling Umgebung ausgelöst. Beachten Sie, dass wie üblich die aufrufbare selbst von Namen gebeizt wird.
Ein Tupel von Argumenten für das aufrufbare Objekt.
Optional der Status des Objekts, der an die Methode __setstate__()
des Objekts übergeben wird, wie im Abschnitt Ein- und Ausbau normaler Klasseninstanzen beschrieben.Wenn das Objekt keine __setstate__()
Methode, hat, dann muss der Wert wie oben beschrieben ein Wörterbuch sein und wird des Objekts __dict__
hinzugefügt. So
ist _reconstruct
die Funktion aufgerufen, das Objekt neu zu erstellen, sind (<class 'pick.RealisticInfoArray'>, (0,), 'b')
die für diese Funktion übergebenen Argumente und (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'))
wird an die Klasse übergeben __setstate__
. Dies gibt uns eine Chance; wir könnten __reduce__
überschreiben und unser eigenes Tupel zu __setstate__
zur Verfügung stellen, und dann außer __setstate__
außer Kraft setzen, um unser kundenspezifisches Attribut zu setzen, wenn wir unpickle. Wir müssen nur sicherstellen, dass wir die übergeordnete Klasse braucht, um alle Daten zu erhalten und rufen die Eltern __setstate__
auch:
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])
Verbrauch:
>>> 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'
groß, daß es behoben hat. Danke auch für das sehr klare Codebeispiel. Ich übertrage tatsächlich über das '__dict__'-Objekt, um dies generischer zu machen. Glücklicherweise scheint np.darray es nicht zu benutzen, also kann ich es für meine eigenen Zwecke verwenden. – Gabriel