Non so cosa fanno i metodi __setstate__
e __getstate__
, quindi aiutami con un semplice esempio.
Risposte:
Ecco un esempio molto semplice per Python che dovrebbe integrare i documenti di 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)
Esempio minimo
Qualunque cosa venga fuori getstate
, entra setstate
. Non è necessario che sia un dettame.
Ciò che viene fuori getstate
deve essere pickeable, ad esempio costituito da built-in di base come 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
Predefinito __setstate__
L'impostazione predefinita __setstate__
richiede un file dict
.
self.__dict__
è una buona scelta come in https://stackoverflow.com/a/1939384/895245 , ma possiamo costruirne uno noi stessi per vedere meglio cosa sta succedendo:
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
Predefinito __getstate__
Analogo a __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__
gli oggetti non hanno __dict__
Se l'oggetto ha __slots__
, allora non ha__dict__
Se hai intenzione di implementare sia get
e setstate
, il modo predefinito è:
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__
Il valore predefinito get and set prevede una tupla
Se vuoi riutilizzare il valore predefinito __getstate__
o __setstate__
, dovrai passare le tuple come:
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
Non sono sicuro di cosa serva.
Eredità
Per prima cosa vedi che il decapaggio funziona di default:
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
Ereditarietà personalizzata __getstate__
Senza __slots__
è facile, poiché il __dict__
for D
contiene il __dict__
for C
, quindi non abbiamo bisogno di toccare C
affatto:
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
Eredità e __slots__
Con __slots__
, dobbiamo inoltrare alla classe base e possiamo passare le tuple in giro:
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
Purtroppo non è possibile riutilizzare il default __getstate__
e __setstate__
della base: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ siamo costretti a definirli.
Testato su Python 2.7.12. GitHub a monte .
Questi metodi vengono utilizzati per controllare come gli oggetti vengono decapati e non selezionati dal modulo pickle . Questo di solito viene gestito automaticamente, quindi, a meno che non sia necessario sovrascrivere il modo in cui una classe viene decapitata o deselezionata, non dovresti preoccupartene.