Tôi không biết những gì __setstate__
và __getstate__
các phương pháp làm, vì vậy hãy giúp tôi với một ví dụ đơn giản.
Câu trả lời:
Đây là một ví dụ rất đơn giản cho Python sẽ bổ sung cho các tài liệu dưa chua .
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)
Ví dụ tối thiểu
Bất cứ điều gì đi ra getstate
, đi vào setstate
. Nó không cần phải là một chính tả.
Dù đi ra getstate
phải pickeable, ví dụ như tạo thành từ các built-in cơ bản như 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
Mặc định __setstate__
Mặc định __setstate__
có a dict
.
self.__dict__
là một lựa chọn tốt như trong https://stackoverflow.com/a/1939384/895245 , nhưng chúng tôi có thể tự xây dựng một lựa chọn để xem rõ hơn những gì đang diễn ra:
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
Mặc định __getstate__
Tương tự với __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__
đồ vật không có __dict__
Nếu đối tượng có __slots__
, thì nó không có__dict__
Nếu bạn định triển khai cả hai get
và setstate
, cách mặc định là:
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__
lấy và đặt mặc định mong đợi một tuple
Nếu bạn muốn sử dụng lại mặc định __getstate__
hoặc __setstate__
, bạn sẽ phải chuyển các bộ giá trị như:
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
Tôi không chắc cái này dùng để làm gì.
Di sản
Trước tiên, hãy thấy rằng quá trình tẩy rửa hoạt động theo mặc định:
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
Phong tục thừa kế __getstate__
Không có __slots__
nó thì thật dễ dàng, vì __dict__
for D
chứa __dict__
for C
, vì vậy chúng ta không cần phải chạm C
và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
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
Kế thừa và __slots__
Với __slots__
, chúng ta cần chuyển tiếp đến lớp cơ sở và có thể chuyển các bộ giá trị xung quanh:
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
Rất tiếc, không thể sử dụng lại mặc định __getstate__
và __setstate__
cơ sở: https://groups.google.com/forum/#!topic/python-ideas/QkvOwa1-pHQ, chúng tôi buộc phải xác định chúng.
Đã thử nghiệm trên Python 2.7.12. GitHub ngược dòng .
Các phương pháp này được sử dụng để kiểm soát cách các đối tượng được chọn và bỏ chọn bởi mô-đun pickle . Điều này thường được xử lý tự động, vì vậy trừ khi bạn cần ghi đè lên cách một lớp được chọn hoặc bỏ chọn, bạn không cần phải lo lắng về nó.