Einfaches Beispiel für die Verwendung von __setstate__ und __getstate__

87

Ich weiß nicht, was die __setstate__und __getstate__Methoden tun, also helfen Sie mir mit einem einfachen Beispiel.

zjm1126
quelle
25
Die Dokumente sind in diesem Punkt sowieso nicht sehr gut.
Matt Luongo

Antworten:

72

Hier ist ein sehr einfaches Beispiel für Python, das die Pickle-Dokumente ergänzen sollte .

class Foo(object):
  def __init__(self, val=2):
     self.val = val
  def __getstate__(self):
     print("I'm being pickled")
     self.val *= 2
     return self.__dict__
  def __setstate__(self, d):
     print("I'm being unpickled with these values: " + repr(d))
     self.__dict__ = d
     self.val *= 3

import pickle
f = Foo()
f_data = pickle.dumps(f)
f_new = pickle.loads(f_data)
BrainCore
quelle
9
Um diese Antwort zu ergänzen, wird "Ich werde eingelegt", dann "Ich werde mit diesen Werten abgeholt: {'val': 4}" und f_new.val ist 12.
timidpueo
39

Minimales Beispiel

Was auch immer herauskommt getstate, geht hinein setstate. Es muss kein Diktat sein.

Was auch immer kommt aus getstatemuss pickeable, zum Beispiel aus dem Grunde Einbauten wie int, str, list.

class C(object):
    def __init__(self, i):
        self.i = i
    def __getstate__(self):
        return self.i
    def __setstate__(self, i):
        self.i = i
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

Standard __setstate__

Der Standardwert ist __setstate__a dict.

self.__dict__ist eine gute Wahl wie unter https://stackoverflow.com/a/1939384/895245 , aber wir können selbst eine erstellen, um besser zu sehen, was los ist:

class C(object):
    def __init__(self, i):
        self.i = i
    def __getstate__(self):
        return {'i': self.i}
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

Standard __getstate__

Analog zu __setstate__.

class C(object):
    def __init__(self, i):
        self.i = i
    def __setstate__(self, d):
        self.i = d['i']
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

__slots__ Objekte haben nicht __dict__

Wenn das Objekt hat __slots__, dann hat es nicht__dict__

Wenn Sie beide getund implementieren setstatemöchten, lautet die Standardeinstellung:

class C(object):
    __slots__ = 'i'
    def __init__(self, i):
        self.i = i
    def __getsate__(self):
        return { slot: getattr(self, slot) for slot in self.__slots__ }
    def __setsate__(self, d):
        for slot in d:
            setattr(self, slot, d[slot])
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

__slots__ Standardmäßig erwartet get and set ein Tupel

Wenn Sie die Standardeinstellung __getstate__oder wiederverwenden möchten __setstate__, müssen Sie Tupel wie folgt weitergeben:

class C(object):
    __slots__ = 'i'
    def __init__(self, i):
        self.i = i
    def __getsate__(self):
        return (None, { slot: getattr(self, slot) for slot in self.__slots__ })
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1

Ich bin mir nicht sicher, wofür das ist.

Erbe

Stellen Sie zunächst sicher, dass das Beizen standardmäßig funktioniert:

class C(object):
    def __init__(self, i):
        self.i = i
class D(C):
    def __init__(self, i, j):
        super(D, self).__init__(i)
        self.j = j
d = pickle.loads(pickle.dumps(D(1, 2), -1))
assert d.i == 1
assert d.j == 2

Vererbungsgewohnheit __getstate__

Ohne __slots__es ist einfach, da die __dict__für Denthält die __dict__für C, so dass wir berühren nicht brauchen Cüberhaupt:

class C(object):
    def __init__(self, i):
        self.i = i
class D(C):
    def __init__(self, i, j):
        super(D, self).__init__(i)
        self.j = j
    def __getstate__(self):
        return self.__dict__
    def __setstate__(self, d):
        self.__dict__ = d
d = pickle.loads(pickle.dumps(D(1, 2), -1))
assert d.i == 1
assert d.j == 2

Vererbung und __slots__

Mit __slots__müssen wir an die Basisklasse weiterleiten und können Tupel weitergeben:

class C(object):
    __slots__ = 'i'
    def __init__(self, i):
        self.i = i
    def __getstate__(self):
        return { slot: getattr(self, slot) for slot in C.__slots__ }
    def __setstate__(self, d):
        for slot in d:
            setattr(self, slot, d[slot])

class D(C):
    __slots__ = 'j'
    def __init__(self, i, j):
        super(D, self).__init__(i)
        self.j = j
    def __getstate__(self):
        return (
            C.__getstate__(self),
            { slot: getattr(self, slot) for slot in self.__slots__ }
        )
    def __setstate__(self, ds):
        C.__setstate__(self, ds[0])
        d = ds[1]
        for slot in d:
            setattr(self, slot, d[slot])

d = pickle.loads(pickle.dumps(D(1, 2), -1))
assert d.i == 1
assert d.j == 2

Leider ist es nicht möglich, die Standardeinstellung __getstate__und __setstate__die Basis wiederzuverwenden : https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ Wir sind gezwungen, sie zu definieren.

Getestet auf Python 2.7.12. GitHub stromaufwärts .

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
9

Diese Methoden werden verwendet zur Steuerung , wie Objekte gebeizt und ungebeizt durch die Beize - Modul. Dies wird normalerweise automatisch erledigt. Wenn Sie also nicht überschreiben müssen, wie eine Klasse ausgewählt oder nicht ausgewählt wird, sollten Sie sich darüber keine Gedanken machen müssen.

Pär Wieslander
quelle