Я не знаю, що роблять методи __setstate__та __getstate__, тому допоможіть мені на простому прикладі.
Відповіді:
Ось дуже простий приклад для Python, який повинен доповнити документи для розсолу .
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)
Мінімальний приклад
Що б не вийшло getstate, входить setstate. Для цього не обов’язково бути диктом.
Все , що виходить з getstateповинні бути pickeable, наприклад , з основних вбудованих функцій , таких як 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__приймається a dict.
self.__dict__це хороший вибір, як у https://stackoverflow.com/a/1939384/895245 , але ми можемо створити його самостійно, щоб краще побачити, що відбувається:
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, спосіб за замовчуванням:
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 and 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__for Dмістить __dict__for 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 вгору за течією .
Ці методи використовуються для управління , як об'єкти мариновані і unpickled в маринаді модуля. Зазвичай це обробляється автоматично, тому, якщо вам не потрібно перевизначити спосіб маринування або розібрання класу, вам не потрібно турбуватися про це.