Nie wiem, co __setstate__
i __getstate__
metody nie, tak mi pomóc z prostym przykładzie.
Odpowiedzi:
Oto bardzo prosty przykład dla Pythona, który powinien uzupełniać dokumentację pickle .
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)
Minimalny przykład
Cokolwiek wychodzi getstate
, wchodzi w setstate
. Nie musi to być dyktando.
Cokolwiek wyjdzie getstate
musi być pickeable np składa się z podstawowych wbudowanych wtyczek takich jak 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
Domyślna __setstate__
Domyślnie __setstate__
zajmuje dict
.
self.__dict__
to dobry wybór, jak na https://stackoverflow.com/a/1939384/895245 , ale możemy sami zbudować taki, aby lepiej widzieć, co się dzieje:
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
Domyślna __getstate__
Analogicznie do __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__
obiekty nie mają __dict__
Jeśli obiekt ma __slots__
, to nie ma__dict__
Jeśli zamierzasz zaimplementować oba get
i setstate
, domyślnym sposobem jest:
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__
Domyślnie get and set oczekuje krotki
Jeśli chcesz ponownie użyć domyślnego __getstate__
lub __setstate__
, będziesz musiał przekazać krotki jako:
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
Nie jestem pewien, do czego to służy.
Dziedzictwo
Najpierw zobacz, że wytrawianie działa domyślnie:
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
Niestandardowe dziedziczenie __getstate__
Bez __slots__
tego jest to łatwe, ponieważ __dict__
for D
zawiera __dict__
for C
, więc nie musimy C
w ogóle dotykać :
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
Dziedziczenie i __slots__
W programie __slots__
musimy przekazać do klasy bazowej i możemy przekazywać krotki wokół:
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
Niestety nie jest możliwe ponowne użycie wartości domyślnych __getstate__
i __setstate__
bazy: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ jesteśmy zmuszeni je zdefiniować.
Przetestowano w Pythonie 2.7.12. GitHub upstream .
Te metody są używane do kontrolowania sposobu wytrawiania i odblokowywania przedmiotów przez moduł marynowania . Zwykle jest to obsługiwane automatycznie, więc nie musisz się tym martwić, chyba że musisz zmienić sposób, w jaki klasa jest marynowana lub odmładzana.