在我的类实例化期间,我初始化一些不可选择的字段。因此,为了能够(un)正确地挑选我的类,我希望在unpickling上调用我的 init 方法。这似乎是它与旧式课程一起使用的方式。
对于新的样式类,我需要使用__new__
和__getnewargs__
。这是我的工作:
import cPickle
class Blubb(object):
def __init__(self, value):
self.value = value
class Bla(Blubb):
def __new__(cls, value):
instance = super(Bla, cls).__new__(cls)
instance.__init__(value)
return instance
def __getnewargs__(self):
return self.value,
def __getstate__(self):
return {}
def __setstate__(self, dct):
pass
x = Bla(2)
print x.value
pickled = cPickle.dumps(x, 2)
x_ = cPickle.loads(pickled)
assert x_.value == 2
如果没有obj = C.__new__(C, *args)
的事实,那就没问题了。现在有**kwargs
。因此,我的__new__
和__init__
方法仅限于非关键字参数。
有谁知道解决这个问题的方法?这真的很不方便。
答案 0 :(得分:7)
pickle协议2默认情况下要调用cls.__new__(cls, *args)
,但有一种解决方法。如果您使用__reduce__
,则可以返回一个函数,该函数将您的参数映射到__new__
。我能够修改您的示例以使**kwargs
起作用:
import cPickle
class Blubb(object):
def __init__(self, value, foo=None, bar=None):
self.value = value
self.foo = foo
self.bar = bar
def _new_Bla(cls, value, kw):
"A function to map kwargs into cls.__new__"
return cls.__new__(cls, value, **kw)
class Bla(Blubb):
def __new__(cls, value, **kw):
instance = super(Bla, cls).__new__(cls)
instance.__init__(value, **kw)
return instance
def __reduce__(self):
kwargs = {'foo': self.foo, 'bar': self.bar}
return _new_Bla, (self.__class__, self.value, kwargs), None
x = Bla(2, bar=[1, 2, 3])
pickled = cPickle.dumps(x, 2)
y = cPickle.loads(pickled)
assert y.value == 2
assert y.bar == [1, 2, 3]