用 kwargs 解封新样式不可能吗?

发布于 2024-10-20 19:30:04 字数 884 浏览 1 评论 0原文

在类的实例化过程中,我初始化了一些不可 picklable 的字段。因此,为了能够正确(取消)pickle 我的类,我希望在 unpickle 时调用我的 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__ 方法中仅限于非关键字参数。

有谁知道解决这个问题的方法吗?这确实很不方便。

During instantiation of my class, I initialize some fields that are not picklable. Thus, in order to be able to (un)pickle my classes correctly, I would like my init method to be called on unpickling. This is, it seems, the way it worked with old-style classes.

With new style classes, I need to use __new__ and __getnewargs__. Here is what I do:

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

This would be fine, if not for the fact that obj = C.__new__(C, *args). There is now **kwargs. So I am restricted to non keyword arguments in my __new__ and __init__ methods.

Does anyone know of a way to solve this? This is really unconvenient.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

私野 2024-10-27 19:30:04

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]

The pickle protocol 2 wants to call cls.__new__(cls, *args) by default, but there is a way around this. If you use __reduce__ you can return a function which will map your arguments to __new__. I was able to modify your example to get **kwargs to work:

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]
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文