python 为什么在尝试pickle对象时会收到关于我的类定义__slots__的错误?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2204155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why am I getting an error about my class defining __slots__ when trying to pickle an object?
提问by Daryl Spitzer
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. Did something I do implicitly define it? How do I work around this? Do I need to define __getstate__
?
我没有__slots__
在我的班级中明确定义。我所做的事情是否隐含地定义了它?我该如何解决这个问题?我需要定义__getstate__
吗?
Update:gnibblerchose a good example. 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. 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.
更新:gnibbler选择了一个很好的例子。我试图腌制的对象的类包装了一个套接字。(现在我突然想到)套接字定义__slots__
并没有__getstate__
充分的理由。我假设一旦一个进程结束,另一个进程就不能解开并使用前一个进程的套接字连接。因此,虽然我接受了Alex Martelli的出色回答,但我将不得不采用与酸洗不同的策略来“共享”对象引用。
回答by 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 graphof references with your object as root, since pickling needs to save the entire graph.
定义__slots__
(而不是__getstate__
)的类可以是您的祖先类,也可以是您的属性或项目的类(或祖先类),直接或间接:本质上,引用的有向图中的任何对象的类您的对象作为根,因为酸洗需要保存整个图形。
A simple solution to your quandary is to use protocol -1
, which means "the best protocol pickle can use"; the default is an ancient ASCII-based protocol which imposes this limitation about __slots__
vs __getstate__
. Consider:
解决您的困境的一个简单方法是使用 protocol -1
,这意味着“可以使用的最佳协议泡菜”;默认是一个古老的基于 ASCII 的协议,它对__slots__
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
>>>
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; the resulting pickled file would not be loadable by sufficiently ancient versions of Python. Advantages, besides the key one wrt __slots__
, include more compact results, and better performance.
协议的问题-1
:它产生一个二进制字符串/文件,而不是像默认协议那样的 ASCII 字符串;生成的腌制文件将无法被足够古老的 Python 版本加载。除了关键的 wrt 之外,优点还__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
协议,那就更好了,不值得讨论;-)并且简单的代码检查寻找麻烦的类/对象被证明太复杂了(我在如果您想知道,请注意一些基于深度复制的技巧以获得整个图形的可用表示)。
回答by John La Rooy
Perhaps an attribute of your instance is using __slots__
也许您的实例的一个属性正在使用 __slots__
For example, socket
has __slots__
so it can't be pickled
例如,socket
有__slots__
所以它不能被腌制
You need to identify which attribute is causing the error and write your own
__getstate__
and __setstate__
to ignore that attribute
您需要确定导致错误的属性并编写自己的
属性__getstate__
并__setstate__
忽略该属性
回答by Joe Koberg
From PEP 307:
来自PEP 307:
The
__getstate__
method should return a picklable value representing the object's state without referencing the object itself. If no__getstate__
method exists, a default implementation is used that returnsself.__dict__
.
该
__getstate__
方法应该返回一个表示对象状态的picklable值,而不引用对象本身。如果不__getstate__
存在任何方法,则使用返回self.__dict__
.