Je ne sais pas ce que font les méthodes __setstate__
et __getstate__
, alors aidez-moi avec un exemple simple.
Réponses:
Voici un exemple très simple pour Python qui devrait compléter la documentation 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)
Exemple minimal
Tout ce qui sort de getstate
, entre setstate
. Il n'est pas nécessaire que ce soit un dict.
Tout ce qui vient de getstate
doit être pickeable, par exemple composé de Encastrements de base comme 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
Défaut __setstate__
La valeur par défaut __setstate__
prend un dict
.
self.__dict__
est un bon choix comme dans https://stackoverflow.com/a/1939384/895245 , mais nous pouvons en construire un nous-mêmes pour mieux voir ce qui se passe:
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
Défaut __getstate__
Analogue à __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__
les objets n'ont pas __dict__
Si l'objet a __slots__
, alors il n'a pas__dict__
Si vous allez implémenter les deux get
et setstate
, la méthode par défaut est:
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__
par défaut, get et set attend un tuple
Si vous souhaitez réutiliser la valeur par défaut __getstate__
ou __setstate__
, vous devrez passer des tuples comme suit:
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
Je ne sais pas à quoi ça sert.
Héritage
Commencez par voir que le décapage fonctionne par défaut:
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
Héritage personnalisé __getstate__
Sans __slots__
c'est facile, puisque le __dict__
for D
contient le __dict__
for C
, nous n'avons donc pas besoin de toucher C
du tout:
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
Héritage et __slots__
Avec __slots__
, nous devons transmettre à la classe de base et pouvons passer des tuples:
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
Malheureusement il n'est pas possible de réutiliser les valeurs par défaut __getstate__
et __setstate__
de la base: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ nous sommes obligés de les définir.
Testé sur Python 2.7.12. GitHub en amont .
Ces méthodes sont utilisées pour contrôler la façon dont les objets sont décapés et décapés par le module pickle . Ceci est généralement géré automatiquement, donc à moins que vous n'ayez besoin de remplacer la façon dont une classe est décapée ou décochée, vous ne devriez pas avoir à vous en soucier.