无法使用kwargs解封新式对象?

5
在我的类实例化期间,我初始化了一些不可picklable的字段。因此,为了能够正确地(取消)pickling我的类,我希望在取消pickling时调用我的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__ 方法中只能使用非关键字参数。是否有人知道解决方法?这真的很不方便。
1个回答

12

默认情况下,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]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接