Я не знаю, что делают методы __setstate__
и __getstate__
, поэтому помогите мне с простым примером.
Простой пример использования __setstate__ и __getstate__
Ответ 1
Вот очень простой пример для Python 2, который должен дополнить pickle docs.
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:", d
self.__dict__ = d
self.val *= 3
import pickle
f = Foo()
f_string = pickle.dumps(f)
f_new = pickle.loads(f_string)
Ответ 2
Минимальный пример
Что бы ни выходило из getstate
, оно попадает в setstate
. Это не должно быть диктом.
Все, что выходит из getstate
должно быть доступным, например, из базовых встроенных функций, таких как 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
По умолчанию __setstate__
Значение по умолчанию __setstate__
принимает dict
.
self.__dict__
- хороший выбор, как и в fooobar.com/questions/149196/..., но мы можем self.__dict__
его сами, чтобы лучше увидеть, что происходит:
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
По умолчанию __getstate__
Аналог __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__
объекты не имеют __dict__
Если объект имеет __slots__
, то он не имеет __dict__
Если вы собираетесь реализовать как get
и setstate
, setstate
по умолчанию ish:
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__
default get и set ожидает кортеж
Если вы хотите повторно использовать стандартные __getstate__
или __setstate__
, вам придется передавать кортежи как:
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
Я не уверен, для чего это.
наследование
Сначала убедитесь, что травление работает по умолчанию:
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
Наследование пользовательских __getstate__
Без __slots__
это легко, поскольку __dict__
для D
содержит __dict__
для C
, поэтому нам вообще не нужно трогать C
:
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
Наследование и __slots__
С __slots__
нам нужно перейти к базовому классу, и мы можем передавать кортежи:
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
К сожалению, невозможно использовать по умолчанию __getstate__
и __setstate__
базы: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ, мы вынуждены их определить.
Проверено на Python 2.7.12. GitHub вверх по течению.
Ответ 3
Эти методы используются для управления тем, как объекты маринуются и рассыпаются модулем pickle. Обычно это обрабатывается автоматически, поэтому, если вам не нужно переопределять способ маринования или рассыпания класса, вам не нужно беспокоиться об этом.