为什么我在尝试 pickle 对象时收到有关定义 __slots__ 的类的错误?
我正在尝试腌制我定义的(新式)类的对象。但我收到以下错误:
>>> 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 选择了一个很好的例子。我试图 pickle 的对象的类包装了一个套接字。 (我现在想到)套接字定义 __slots__
而不是 __getstate__
是有充分理由的。我假设一旦一个进程结束,另一个进程就无法取消并使用前一个进程的套接字连接。因此,虽然我接受 Alex Martelli 的出色答案,但我将不得不采取不同的策略而不是通过酸洗来“共享”对象引用。
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__
?
Update: gnibbler chose 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
定义
__slots__
的类(而不是 < a href="https://docs.python.org/2/library/pickle.html#object.__getstate__" rel="noreferrer">__getstate__
) 可以是祖先您的类,或者您的属性或项目的类(或祖先类),直接或间接:本质上,是以您的对象为根的引用有向图中中任何对象的类,因为 pickling 需要保存整个图。解决您的困境的一个简单方法是使用协议
-1
,这意味着“pickle 可以使用的最佳协议”;默认值是一个古老的基于 ASCII 的协议,它对__slots__
与__getstate__
施加了此限制。考虑一下:如您所见,协议
-1
大步接受__slots__
,而默认协议给出了与您看到的相同的异常。协议
-1
的问题:它生成一个二进制字符串/文件,而不是像默认协议那样生成 ASCII 字符串/文件;生成的 pickle 文件将无法被足够古老的 Python 版本加载。除了与__slots__
相关的关键优势之外,其优点还包括更紧凑的结果和更好的性能。如果您被迫使用默认协议,那么您需要准确识别哪个类给您带来了麻烦以及确切的原因。如果是这种情况,我们可以讨论策略(但如果你可以使用
-1
协议,那就好多了,不值得讨论;-)和简单的代码检查寻找麻烦的类/事实证明对象太复杂了(我想到了一些基于深度复制的技巧来获得整个图的可用表示,以防您想知道)。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.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:As you see, protocol
-1
takes the__slots__
in stride, while the default protocol gives the same exception you saw.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.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).也许您的实例的某个属性正在使用
__slots__
例如,
socket
有__slots__
因此它无法被 pickle您需要确定哪个属性是导致错误并编写自己的
__getstate__
和__setstate__
忽略该属性Perhaps an attribute of your instance is using
__slots__
For example,
socket
has__slots__
so it can't be pickledYou need to identify which attribute is causing the error and write your own
__getstate__
and__setstate__
to ignore that attribute来自 PEP 307:
From PEP 307: