简体   繁体   English

为什么我在尝试挑选一个对象时遇到定义__slots__的类的错误?

[英]Why am I getting an error about my class defining __slots__ when trying to pickle an object?

I'm trying to pickle an object of a (new-style) class I defined. 我正在尝试挑选我定义的(新式)类的对象。 But I'm getting the following error: 但是我收到以下错误:

>>> 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

I didn't explicitly define __slots__ in my class. 我没有在班上明确定义__slots__ Did something I do implicitly define it? 我做了什么隐含地定义它? How do I work around this? 我该如何解决这个问题? Do I need to define __getstate__ ? 我需要定义__getstate__吗?

Update: gnibbler chose a good example. 更新: gnibbler选择了一个很好的例子。 The class of the object I'm trying to pickle wraps a socket. 我试图挑选的对象的类包装了一个套接字。 (It occurs to me now that) sockets define __slots__ and not __getstate__ for good reason. (现在发生在我身上)套接字有充分的理由定义__slots__而不是__getstate__ I assume once a process ends, another process can't unpickle and use the previous process's socket connection. 我假设一旦进程结束,另一个进程就无法解开并使用前一进程的套接字连接。 So while I'm accepting Alex Martelli 's excellent answer, I'm going to have to pursue a different strategy than pickling to "share" the object reference. 因此,虽然我接受Alex Martelli的优秀答案,但我将不得不采取不同的策略,而不是挑选“分享”对象参考。

The class defining __slots__ (and not __getstate__ ) can be either an ancestor class of yours, or a class (or ancestor class) of an attribute or item of yours, directly or indirectly: essentially, the class of any object in the directed graph of references with your object as root, since pickling needs to save the entire graph. 的类中定义__slots__ (而不是__getstate__ )可以是一个父类你的,或一个类(或祖先类)你的属性或项目时,直接或间接地:基本上,所述类中的任何对象的在有向图以root身份引用您的对象,因为pickling需要保存整个图形。

A simple solution to your quandary is to use protocol -1 , which means "the best protocol pickle can use"; 您的困境的一个简单解决方案是使用协议-1 ,这意味着“最好的协议泡菜可以使用”; the default is an ancient ASCII-based protocol which imposes this limitation about __slots__ vs __getstate__ . 默认是一个古老的基于ASCII的协议,它对__slots__ vs __getstate__强加了这个限制。 Consider: 考虑:

>>> 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
>>> 

As you see, protocol -1 takes the __slots__ in stride, while the default protocol gives the same exception you saw. 如您所见,协议-1在步幅中采用__slots__ ,而默认协议提供您看到的相同异常。

The issues with protocol -1 : it produces a binary string/file, rather than an ASCII one like the default protocol; 协议-1的问题:它产生二进制字符串/文件,而不是像默认协议那样的ASCII字符串/文件; the resulting pickled file would not be loadable by sufficiently ancient versions of Python. 足够古老的Python版本无法加载生成的pickle文件。 Advantages, besides the key one wrt __slots__ , include more compact results, and better performance. 除了关键的一个__slots__之外,优点还包括更紧凑的结果和更好的性能。

If you're forced to use the default protocol, then you'll need to identify exactly which class is giving you trouble and exactly why. 如果您被迫使用默认协议,那么您需要确切地确定哪个类给您带来麻烦以及确切原因。 We can discuss strategies if this is the case (but if you can possibly use the -1 protocol, that's so much better that it's not worth discussing;-) and simple code inspection looking for the troublesome class/object is proving too complicated (I have in mind some deepcopy-based tricks to get a usable representation of the whole graph, in case you're wondering). 如果是这种情况,我们可以讨论策略(但如果你可以使用-1协议,那就更好了,不值得讨论;-)并且简单的代码检查寻找麻烦的类/对象证明太复杂(我考虑到一些基于深度复制的技巧,以获得整个图形的可用表示,以防你想知道)。

Perhaps an attribute of your instance is using __slots__ 也许您的实例的属性正在使用__slots__

For example, socket has __slots__ so it can't be pickled 例如, socket具有__slots__因此无法进行pickle

You need to identify which attribute is causing the error and write your own __getstate__ and __setstate__ to ignore that attribute 您需要确定导致错误的属性并编写自己的__getstate____setstate__来忽略该属性

From PEP 307 : PEP 307

The __getstate__ method should return a picklable value representing the object's state without referencing the object itself. __getstate__方法应返回表示对象状态的__getstate__值,而不引用对象本身。 If no __getstate__ method exists, a default implementation is used that returns self.__dict__ . 如果不存在__getstate__方法,则使用返回self.__dict__的默认实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM