Python酸洗槽错误

时间:2010-08-19 14:27:00

标签: python pickle

我有一个很大的实例,我一直在酸洗,但最近我尝试转储它时开始收到此错误:

  File "/usr/lib/python2.6/copy_reg.py", line 77, in _reduce_ex
    raise TypeError("a class that defines __slots__ without "
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled

我不明白这个错误,因为我的所有类似乎都定义了__getstate__方法,似乎都没有定义__slots__。我无法隔离更改,因此触发了此错误。

我只能假设我的实例中有一些嵌套在深层的对象导致了这个问题。有没有办法获得更多信息?如何找到触发此错误的确切对象的类?

2 个答案:

答案 0 :(得分:13)

使用二进制协议进行酸洗(而不是您似乎默认的旧ASCII),你会没事的。观察:

>>> class ws(object):
...   __slots__ = 'a', 'b'
...   def __init__(self, a=23, b=45): self.a, self.b = a, b
... 
>>> x = ws()
>>> import pickle
>>> pickle.dumps(x, -1)
'\x80\x02c__main__\nws\nq\x00)\x81q\x01N}q\x02(U\x01aq\x03K\x17U\x01bq\x04K-u\x86q\x05b.'
>>> pickle.dumps(x)
Traceback (most recent call last):
    [[snip]]
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/copy_reg.py", line 77, in _reduce_ex
    raise TypeError("a class that defines __slots__ without "
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled
>>> 

如您所见,-1协议(表示“最好,最快,最紧凑的协议”)工作得很好,而默认的0协议(旧的ascii协议设计为兼容)一直回到Python 1.5及更早版本)给出了你所观察到的异常。

此外,-1会更快并且会产生更紧凑的结果 - 您只需确保正确保存并恢复其生成的二进制字符串(因此,例如,如果您正在挑选文件,请确保为wb打开后者,只打w)。

如果出于某种原因,您无法使用这种全能解决方案,那么有一些黑客和技巧(例如,子类pickle.Pickler,直接使用您的子类的实例而不是基类的实例{{ 1}}会覆盖pickle.dumps方法,以便在委托给超类之前跟踪save,但升级到右边,最新的协议(type(obj)是有保证的无论如何,在任何给定的Python版本上,版本支持的最高级版本都是个好主意,如果可行的话。

答案 1 :(得分:1)

我也遇到了这个问题,但旧的ASCII协议中有一些已经被腌制的数据。 您可以使用这些方法使插槽适应您的对象:

class MyAlreadyPickeldObjectWithslots(object):
    ___slots__= ("attr1","attr2",....)
    def __getstate__(self):
        return dict([(k, getattr(self,k,None)) for k in self.__slots__])

    def __setstate__(self,data):
        for k,v in data.items():
            setattr(self,k,v)

这可以用来获得大量的RAM