29

我正在尝试腌制我定义的(新型)类的对象。但我收到以下错误:

>>> with open('temp/connection.pickle','w') as f:
...   pickle.dump(c,f)
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/usr/lib/python2.5/pickle.py", line 1362, in dump
    Pickler(file, protocol).dump(obj)
  File "/usr/lib/python2.5/pickle.py", line 224, in dump
    self.save(obj)
  File "/usr/lib/python2.5/pickle.py", line 331, in save
    self.save_reduce(obj=obj, *rv)
  File "/usr/lib/python2.5/pickle.py", line 419, in save_reduce
    save(state)
  File "/usr/lib/python2.5/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.5/pickle.py", line 649, in save_dict
    self._batch_setitems(obj.iteritems())
  File "/usr/lib/python2.5/pickle.py", line 663, in _batch_setitems
    save(v)
  File "/usr/lib/python2.5/pickle.py", line 306, in save
    rv = reduce(self.proto)
  File "/usr/lib/python2.5/copy_reg.py", line 76, in _reduce_ex
    raise TypeError("a class that defines __slots__ without "
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled

我没有__slots__在课堂上明确定义。我所做的事情是否隐含地定义了它?我该如何解决这个问题?我需要定义__getstate__吗?

更新: gnibbler选择了一个很好的例子。我试图腌制的对象的类包装了一个套接字。(我现在想到)套接字定义__slots__并没有__getstate__充分的理由。我假设一旦一个进程结束,另一个进程就不能解开并使用前一个进程的套接字连接。因此,虽然我接受了Alex Martelli的出色回答,但我将不得不采取与酸洗不同的策略来“共享”对象引用。

4

3 回答 3

31

定义__slots__(而不是__getstate__)的类可以是您的祖先类,也可以是您的属性或项目的类(或祖先类),直接或间接:本质上,有向引用中的任何对象的类您的对象作为根,因为酸洗需要保存整个图形。

一个简单的解决方案是使用协议-1,这意味着“泡菜可以使用的最佳协议”;__slots__默认是一个古老的基于 ASCII 的协议,它对vs施加了这个限制__getstate__。考虑:

>>> class sic(object):
...   __slots__ = 'a', 'b'
... 
>>> import pickle
>>> pickle.dumps(sic(), -1)
'\x80\x02c__main__\nsic\nq\x00)\x81q\x01.'
>>> pickle.dumps(sic())
Traceback (most recent call last):
  [snip snip]
    raise TypeError("a class that defines __slots__ without "
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled
>>> 

如您所见,协议大步向前,而默认协议提供了与您看到的相同的异常-1__slots__

协议的问题-1:它产生一个二进制字符串/文件,而不是像默认协议那样的 ASCII 文件;由此产生的腌制文件将无法被足够古老的 Python 版本加载。除了关键的一项之外,优点还__slots__包括更紧凑的结果和更好的性能。

如果您被迫使用默认协议,那么您需要准确确定哪个类给您带来麻烦以及确切原因。如果是这种情况,我们可以讨论策略(但是如果您可以使用-1协议,那就更好了,不值得讨论;-)并且寻找麻烦的类/对象的简单代码检查被证明太复杂了(我在如果您想知道,请注意一些基于 deepcopy 的技巧来获得整个图的可用表示)。

于 2010-02-05T02:35:10.907 回答
6

也许您的实例的属性正在使用__slots__

例如,socket__slots__所以它不能被腌制

您需要确定导致错误的属性并编写自己的 属性__getstate____setstate__忽略该属性

于 2010-02-05T00:06:34.240 回答
2

来自PEP 307

__getstate__方法应该返回一个表示对象状态的可挑选值,而不引用对象本身。如果不__getstate__存在方法,则使用返回的默认实现self.__dict__

于 2010-02-05T00:04:26.280 回答