No sé qué hacen los métodos __setstate__y __getstate__, así que ayúdame con un ejemplo simple.
Respuestas:
Aquí hay un ejemplo muy simple de Python que debería complementar los documentos de 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)
Ejemplo mínimo
De todo lo que sale getstate, entra setstate. No tiene por qué ser un dict.
Lo que sale de getstatedebe ser pickeable, por ejemplo, formada por muebles empotrados básicos como 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
Defecto __setstate__
El valor predeterminado __setstate__toma un dict.
self.__dict__es una buena opción como en https://stackoverflow.com/a/1939384/895245 , pero podemos construir uno nosotros mismos para ver mejor lo que está sucediendo:
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
Defecto __getstate__
Análogo 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__ los objetos no tienen __dict__
Si el objeto tiene __slots__, entonces no tiene__dict__
Si va a implementar ambos gety setstate, la forma predeterminada es:
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__ predeterminado get y set espera una tupla
Si desea reutilizar el valor predeterminado __getstate__o __setstate__, tendrá que pasar tuplas como:
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
No estoy seguro para qué es esto.
Herencia
Primero vea que el decapado funciona por defecto:
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
Herencia personalizada __getstate__
Sin __slots__ella es fácil, ya que la __dict__for Dcontiene la __dict__for C, por lo que no necesitamos tocar Cen absoluto:
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
Herencia y __slots__
Con __slots__, necesitamos reenviar a la clase base y podemos pasar tuplas:
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
Lamentablemente no es posible reutilizar los predeterminados __getstate__y __setstate__de la base: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ nos vemos obligados a definirlos.
Probado en Python 2.7.12. GitHub aguas arriba .
Estos métodos se utilizan para controlar cómo el módulo de encurtidos encurtidos y despemados los objetos . Por lo general, esto se maneja automáticamente, por lo que, a menos que necesite anular la forma en que se encurtió o despejó una clase, no debería tener que preocuparse por eso.