zjm*_*126 65 python serialization
我不知道__setstate__
和 __getstate__
方法有什么关系,所以请帮我一个简单的例子.
Bra*_*ore 60
这是Python 2的一个非常简单的例子,它应该补充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:", d
self.__dict__ = d
self.val *= 3
import pickle
f = Foo()
f_string = pickle.dumps(f)
f_new = pickle.loads(f_string)
Run Code Online (Sandbox Code Playgroud)
Cir*_*四事件 29
最小的例子
无论发生什么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
Run Code Online (Sandbox Code Playgroud)
默认 __setstate__
默认__setstate__
需要一个dict
.
self.__dict__
是一个很好的选择,如/sf/answers/135756911/,但我们可以自己构建一个,以便更好地了解发生了什么:
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
Run Code Online (Sandbox Code Playgroud)
默认 __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
Run Code Online (Sandbox Code Playgroud)
__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
Run Code Online (Sandbox Code Playgroud)
__slots__
默认的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
Run Code Online (Sandbox Code Playgroud)
我不确定这是为了什么.
遗产
首先看到酸洗工作默认情况下:
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
Run Code Online (Sandbox Code Playgroud)
继承自定义 __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
Run Code Online (Sandbox Code Playgroud)
继承与传承 __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
Run Code Online (Sandbox Code Playgroud)
遗憾的是,无法重复使用默认值__getstate__
和__setstate__
基数:https://groups.google.com/forum/#!topic/python-subas/QkvOwa1-pHQ我们不得不定义它们.
在Python 2.7.12上测试过.GitHub上游.
对@BrainCore 答案的澄清。实际上,您可能不想修改self
inside __getstate__
。相反,构造一个将被腌制的新对象,保持原始对象不变以供进一步使用。看起来是这样的:
import pickle
class Foo:
def __init__(self, x:int=2, y:int=3):
self.x = x
self.y = y
self.z = x*y
def __getstate__(self):
# Create a copy of __dict__ to modify values and return;
# you could also construct a new dict (or other object) manually
out = self.__dict__.copy()
out["x"] *= 3
out["y"] *= 10
# You can remove attributes, but note they will not get set with
# some default value in __setstate__ automatically; you would need
# to write a custom __setstate__ method yourself; this might be
# useful if you have unpicklable objects that need removing, or perhaps
# an external resource that can be reloaded in __setstate__ instead of
# pickling inside the stream
del out["z"]
return out
# The default __setstate__ will update Foo's __dict__;
# so no need for a custom implementation here if __getstate__ returns a dict;
# Be aware that __init__ is not called by default; Foo.__new__ gets called,
# and the empty object is modified by __setstate__
f = Foo()
f_str = pickle.dumps(f)
f2 = pickle.loads(f_str)
print("Pre-pickle:", f.x, f.y, hasattr(f,"z"))
print("Post-pickle:", f2.x, f2.y, hasattr(f2,"z"))
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
26460 次 |
最近记录: |