4
import cPickle

class Foo(object):
    def __init__(self):
        self._data = {'bar': 'baz'}

    def __getattr__(self, name):
        assert hasattr(self, '_data')
        return self._data[name]

    # I even had to define this just to stop KeyError: '__getstate__'
    def __getstate__(self):
        return self.__dict__

foo = Foo()
bar = cPickle.dumps(foo)
cPickle.loads(bar)

这会引发断言错误。

我以为pickle/cPickle只是__dict__在转储时变成一个字符串,然后__dict__在加载时使用该字符串直接设置新对象的。为什么dumps需要打电话bar.__getattr__?我该如何改变Foo以避免这种情况?

4

1 回答 1

4

根据 cPickle 的文档:http: //docs.python.org/library/pickle.html

object.__getstate__()

类可以进一步影响其实例的腌制方式;如果类定义了方法__getstate__(),它会被调用,并且返回状态被腌制为实例的内容,而不是实例字典的内容。如果没有__getstate__()方法,则实例的__dict__被腌制。

笔记

在 unpickling 时,可能会在实例上调用一些方法,如__getattr__()__getattribute__()或。__setattr__()如果这些方法依赖于某些内部不变量为真,则该类型应该实现__getinitargs__()__getnewargs__()建立这样的不变量;否则,既__new__()不会也 __init__()不会被调用。

由于您试图断言这hasattr(self, '_data')是真的,我相信您需要使用__getinitargs__()or __getnewargs__()。这是因为在使用 pickle 时,__init__不会调用 classes 方法。

于 2012-08-24T03:09:05.987 回答