__setstate__ 和 __getstate__ 的简单使用示例
我不知道 __setstate__
和 __getstate__
这两个方法是干什么的,能给我一个简单的例子吗?
4 个回答
这些方法是用来控制对象在被“腌制”(也就是序列化)和“解腌”(也就是反序列化)时的行为,主要是通过pickle模块来实现的。一般情况下,这些过程都是自动处理的,所以如果你不需要改变一个类的腌制或解腌方式,通常就不需要担心这些了。
最小示例
从 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
import pickle
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1
默认的 __setstate__
默认的 __setstate__
接受一个 dict
(字典)。
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
,默认的方法是:
class C(object):
__slots__ = 'i'
def __init__(self, i):
self.i = i
def __getstate__(self):
return { slot: getattr(self, slot) for slot in self.__slots__ }
def __setstate__(self, d):
for slot in d:
setattr(self, slot, d[slot])
assert pickle.loads(pickle.dumps(C(1), -1)).i == 1
__slots__
默认的获取和设置期望一个元组
如果你想重用默认的 __getstate__
或 __setstate__
,你需要传递元组:
class C(object):
__slots__ = 'i'
def __init__(self, i):
self.i = i
def __getstate__(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__
,这很简单,因为 D
的 __dict__
包含了 C
的 __dict__
,所以我们根本不需要碰 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__
:这个链接 中提到,我们被迫定义它们。
在 Python 2.7.12 上测试过。GitHub 上的相关代码。
这里有一个非常简单的Python示例,可以帮助你更好地理解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)
输出结果:
I'm being pickled
I'm being unpickled with these values: {'val': 4}