Não sei o que os métodos __setstate__
e __getstate__
fazem, então me ajude com um exemplo simples.
Respostas:
Aqui está um exemplo muito simples para Python que deve complementar a documentação do 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)
Exemplo mínimo
O que quer que saia getstate
, entra setstate
. Não precisa ser um ditado.
O que quer que sai getstate
deve ser pickeable, por exemplo composta de built-ins 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
Padrão __setstate__
O padrão __setstate__
leva a dict
.
self.__dict__
é uma boa escolha como em https://stackoverflow.com/a/1939384/895245 , mas podemos construir um para ver melhor o que está acontecendo:
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
Padrão __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__
objetos não têm __dict__
Se o objeto tem __slots__
, então ele não tem__dict__
Se você for implementar get
e setstate
, a maneira padrão é:
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__
get e set padrão esperam uma tupla
Se você quiser reutilizar o padrão __getstate__
ou __setstate__
, terá que passar as 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
Não sei para que serve.
Herança
Primeiro, veja se a decapagem funciona por padrão:
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
Herança personalizada __getstate__
Sem __slots__
isso é fácil, já que o __dict__
for D
contém o __dict__
for C
, então não precisamos tocar C
em:
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
Herança e __slots__
Com __slots__
, precisamos encaminhar para a classe base e podemos passar 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
Infelizmente não é possível reutilizar o padrão __getstate__
e __setstate__
da base: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ somos obrigados a defini-los.
Testado em Python 2.7.12. GitHub upstream .
Estes métodos são utilizados para controlar a forma como os objectos são decapados e unpickled pela salmoura módulo. Isso geralmente é feito automaticamente, então, a menos que você precise substituir a forma como uma classe é em conserva ou não, você não precisa se preocupar com isso.