Python 如何判断哪个对象属性pickle失败?

Python 如何判断哪个对象属性pickle失败?,python,serialization,Python,Serialization,当您pickle具有某些无法pickle的属性的对象时,该对象将失败,并显示一般错误消息,如: PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed 这是输出: now with instancemethod... Traceback (most recent call last): File "/home/wilbert/d

当您pickle具有某些无法pickle的属性的对象时,该对象将失败,并显示一般错误消息,如:

PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed
这是输出:

now with instancemethod...
Traceback (most recent call last):
  File "/home/wilbert/develop/workspace/Playground/src/misc/picklefail.py", line 15, in <module>
    pickle.dumps(test)
  File "/home/wilbert/lib/python2.5/copy_reg.py", line 69, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle instancemethod objects
现在使用instancemethod。。。
回溯(最近一次呼叫最后一次):
文件“/home/wilbert/develope/workspace/playway/src/misc/picklefail.py”,第15行,在
泡菜倾倒(测试)
文件“/home/wilbert/lib/python2.5/copy_reg.py”,第69行,在
raise TypeError,“无法pickle%s对象”%base.\u\n__
TypeError:无法pickle instancemethod对象

不幸的是,没有任何迹象表明属性
test\u meth
会导致问题。

您可能会因为没有包含更多有用的错误消息而对Python提出错误。同时,在
copy\u reg.py
中修改
\u reduce\u ex()
函数

if base is self.__class__:
    print self # new   
    raise TypeError, "can't pickle %s objects" % base.__name__
输出:

<bound method ?.test_func of <__main__.Test object at 0xb7f4230c>>
Traceback (most recent call last):
  File "nopickle.py", line 14, in ?
    pickle.dumps(test)
  File "/usr/lib/python2.4/copy_reg.py", line 69, in _reduce_ex
    raise TypeError, "can't pickle %s objects" % base.__name__
TypeError: can't pickle instancemethod objects

回溯(最近一次呼叫最后一次):
文件“nopickle.py”,第14行,在?
泡菜倾倒(测试)
文件“/usr/lib/python2.4/copy_reg.py”,第69行,在
raise TypeError,“无法pickle%s对象”%base.\u\n__
TypeError:无法pickle instancemethod对象

我遇到了与您相同的问题,但我的类有点复杂(即类似对象的大型树),因此打印没有多大帮助,所以我拼凑了一个帮助函数。它不完整,仅用于酸洗协议2: 这足够让我找到我的问题。如果你想把它扩展到涵盖所有的内容,协议在我已经把这篇文章编辑好了,这样每个人都可以更新代码

import pickle
def get_pickling_errors(obj,seen=None):
    if seen == None:
        seen = []
    try:
        state = obj.__getstate__()
    except AttributeError:
        return
    if state == None:
        return
    if isinstance(state,tuple):
        if not isinstance(state[0],dict):
            state=state[1]
        else:
            state=state[0].update(state[1])
    result = {}    
    for i in state:
        try:
            pickle.dumps(state[i],protocol=2)
        except pickle.PicklingError:
            if not state[i] in seen:
                seen.append(state[i])
                result[i]=get_pickling_errors(state[i],seen)
    return result
一个使用示例,其中K是不pickle的对象

>>> get_pickling_errors(K)
{'_gen': {}, '_base': {'_gens': None}}

这意味着attibute K.\u gen是不可拾取的,K.\u base.\u gens也是如此。

我发现,如果您对Pickler进行子类化并尝试包装Pickler.save()方法,除了block

import pickle
class MyPickler (pickle.Pickler):
    def save(self, obj):
        try:
            pickle.Pickler.save(self, obj)
        except Exception, e:
            import pdb;pdb.set_trace()
那就这样说吧

import StringIO
output = StringIO.StringIO()
MyPickler(output).dump(thingee)

如果你使用dill,你的例子不会失败

>>> import dill
>>> import new
>>> 
>>> class Test(object):
...     pass
... 
>>> def test_func(self):
...     pass
... 
>>> test = Test()
>>> dill.dumps(test)
'\x80\x02cdill.dill\n_create_type\nq\x00(cdill.dill\n_load_type\nq\x01U\x08TypeTypeq\x02\x85q\x03Rq\x04U\x04Testq\x05h\x01U\nObjectTypeq\x06\x85q\x07Rq\x08\x85q\t}q\n(U\r__slotnames__q\x0b]q\x0cU\n__module__q\rU\x08__main__q\x0eU\x07__doc__q\x0fNutq\x10Rq\x11)\x81q\x12}q\x13b.'
>>> test.test_meth = new.instancemethod(test_func, test)
>>> dill.dumps(test)
'\x80\x02cdill.dill\n_create_type\nq\x00(cdill.dill\n_load_type\nq\x01U\x08TypeTypeq\x02\x85q\x03Rq\x04U\x04Testq\x05h\x01U\nObjectTypeq\x06\x85q\x07Rq\x08\x85q\t}q\n(U\r__slotnames__q\x0b]q\x0cU\n__module__q\rU\x08__main__q\x0eU\x07__doc__q\x0fNutq\x10Rq\x11)\x81q\x12}q\x13U\ttest_methq\x14h\x01U\nMethodTypeq\x15\x85q\x16Rq\x17cdill.dill\n_create_function\nq\x18(cdill.dill\n_unmarshal\nq\x19Ubc\x01\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00C\x00\x00\x00s\x04\x00\x00\x00d\x00\x00S(\x01\x00\x00\x00N(\x00\x00\x00\x00(\x01\x00\x00\x00t\x04\x00\x00\x00self(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\t\x00\x00\x00test_func\x01\x00\x00\x00s\x02\x00\x00\x00\x00\x01q\x1a\x85q\x1bRq\x1cc__builtin__\n__main__\nU\ttest_funcq\x1dNN}q\x1etq\x1fRq h\x12N\x87q!Rq"sb.'
>>> class Unpicklable(object):
...   def breakme(self):
...     self.x = iter(set())
... 
>>> u = Unpicklable()
>>> dill.dumps(u)
'\x80\x02cdill.dill\n_create_type\nq\x00(cdill.dill\n_load_type\nq\x01U\x08TypeTypeq\x02\x85q\x03Rq\x04U\x0bUnpicklableq\x05h\x01U\nObjectTypeq\x06\x85q\x07Rq\x08\x85q\t}q\n(U\r__slotnames__q\x0b]q\x0cU\n__module__q\rU\x08__main__q\x0eU\x07breakmeq\x0fcdill.dill\n_create_function\nq\x10(cdill.dill\n_unmarshal\nq\x11U\xafc\x01\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00C\x00\x00\x00s"\x00\x00\x00d\x01\x00d\x00\x00l\x00\x00}\x01\x00t\x01\x00t\x02\x00\x83\x00\x00\x83\x01\x00|\x00\x00_\x03\x00d\x00\x00S(\x02\x00\x00\x00Ni\xff\xff\xff\xff(\x04\x00\x00\x00t\t\x00\x00\x00itertoolst\x04\x00\x00\x00itert\x03\x00\x00\x00sett\x01\x00\x00\x00x(\x02\x00\x00\x00t\x04\x00\x00\x00selfR\x00\x00\x00\x00(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00<stdin>t\x07\x00\x00\x00breakme\x02\x00\x00\x00s\x04\x00\x00\x00\x00\x01\x0c\x01q\x12\x85q\x13Rq\x14c__builtin__\n__main__\nh\x0fNN}q\x15tq\x16Rq\x17U\x07__doc__q\x18Nutq\x19Rq\x1a)\x81q\x1b}q\x1cb.'
>>> u.breakme()
>>> dill.dumps(u)
Traceback (most recent call last):
…(snip)… 
pickle.PicklingError: Can't pickle <type 'setiterator'>: it's not found as __builtin__.setiterator
>>>
如果错误消息不好,我可以使用
dill.detect
查看顶级对象包含哪些不可拼接的对象

>>> dill.detect.badobjects(u, depth=1)
{'__hash__': <method-wrapper '__hash__' of Unpicklable object at 0x10a37b350>, '__setattr__': <method-wrapper '__setattr__' of Unpicklable object at 0x10a37b350>, '__reduce_ex__': <built-in method __reduce_ex__ of Unpicklable object at 0x10a37b350>, '__reduce__': <built-in method __reduce__ of Unpicklable object at 0x10a37b350>, '__str__': <method-wrapper '__str__' of Unpicklable object at 0x10a37b350>, '__format__': <built-in method __format__ of Unpicklable object at 0x10a37b350>, '__getattribute__': <method-wrapper '__getattribute__' of Unpicklable object at 0x10a37b350>, '__delattr__': <method-wrapper '__delattr__' of Unpicklable object at 0x10a37b350>, 'breakme': <bound method Unpicklable.breakme of <__main__.Unpicklable object at 0x10a37b350>>, '__repr__': <method-wrapper '__repr__' of Unpicklable object at 0x10a37b350>, '__dict__': {'x': <setiterator object at 0x10a370820>}, 'x': <setiterator object at 0x10a370820>, '__sizeof__': <built-in method __sizeof__ of Unpicklable object at 0x10a37b350>, '__init__': <method-wrapper '__init__' of Unpicklable object at 0x10a37b350>}
>>> dill.detect.badtypes(u, depth=1)
{'__hash__': <type 'method-wrapper'>, '__setattr__': <type 'method-wrapper'>, '__reduce_ex__': <type 'builtin_function_or_method'>, '__reduce__': <type 'builtin_function_or_method'>, '__str__': <type 'method-wrapper'>, '__format__': <type 'builtin_function_or_method'>, '__getattribute__': <type 'method-wrapper'>, '__delattr__': <type 'method-wrapper'>, 'breakme': <type 'instancemethod'>, '__repr__': <type 'method-wrapper'>, '__dict__': <type 'dict'>, 'x': <type 'setiterator'>, '__sizeof__': <type 'builtin_function_or_method'>, '__init__': <type 'method-wrapper'>}
>>> set(dill.detect.badtypes(u, depth=1).values())
set([<type 'dict'>, <type 'method-wrapper'>, <type 'instancemethod'>, <type 'setiterator'>, <type 'builtin_function_or_method'>])
>dill.detect.badobjects(u,深度=1)
("hash","setattr","reduce"ex","reduce","str","format","getattribute","delattr"breakme","breakme"repr","dictu"""","initux"",""inituu"""""
>>>dill.detect.badtypes(u,深度=1)
("hash","setattr","reduce"ex","reduce","str","format","getattribute","delattr"breakme","breakme"repr","dictu"","x"","initu"""","initu"",
>>>set(dill.detect.badtypes(u,depth=1).values())
集合([,])
dill
不依赖于存在的
\uuu getstate\uuuu
方法,尽管如果它存在,它可能应该使用它。您还可以使用
objgraph
来获取所有对象依赖项的图片,这些对象依赖项用于构建不需要pickle的对象。它可以帮助您根据上述信息找出问题的根源


请参阅本期中的dill.detect用于跟踪不可粘贴的项目:

您可以举一个失败属性的小例子吗?或者至少再显示一点回溯,看看pickle模块的哪里出了问题?哦,你使用的是哪种Python版本?@MrTopf:添加了信息谢谢,但实际上我认为你唯一的选择确实是修补(并提交错误报告)。为什么不简单地放上“self”我相信这涵盖了示例中的“TypeError”异常,但是原始的“PicklingError”异常没有得到解决。我认为这应该是Python的一部分,很难相信公认的答案是修改python发行版并重新编译。(1) 您可以在不修改python的情况下执行相同的操作,(2)如果要执行此操作,请至少向python提交一个修补程序。@dashesy:mine和其他两个答案都是查找导致pickle错误的属性的可行方法
dill.detect
可用于检查哪些对象无法使用
dill
进行pickle。如果您感兴趣的库使用
pickle
,并且您想使用
dill
…只需键入
import dill
,它将
dill
注册的类型加载到
pickle
注册表中…而无需编辑第三方代码。如果您想使用
dill
来检测错误,而不是扩充python的
pickle
模块,那么键入:
dill.extend(False)
。这不就是启动调试器吗?例如,仅使用Eclipse PyDev调试器来查看问题是否有任何区别?如果PyDev调试器将在异常情况下启动并将您置于正确的执行级别,则是相同的。但我不使用IDE,我用它来定位一个特别难以找到的Pickle错误。但是,我没有让except子句启动调试器,而是让它打印obj并引发异常。然后,运行MyPickler(output).dump(obj)生成了一个类似于回溯的报告,精确地报告了不可点击对象在我的深度嵌套结构中的位置。多好的一天啊。谢谢,这很有帮助。我认为应该在相应的类中定义
\uu getstate\uu()
>>> dill.detect.badobjects(u, depth=1)
{'__hash__': <method-wrapper '__hash__' of Unpicklable object at 0x10a37b350>, '__setattr__': <method-wrapper '__setattr__' of Unpicklable object at 0x10a37b350>, '__reduce_ex__': <built-in method __reduce_ex__ of Unpicklable object at 0x10a37b350>, '__reduce__': <built-in method __reduce__ of Unpicklable object at 0x10a37b350>, '__str__': <method-wrapper '__str__' of Unpicklable object at 0x10a37b350>, '__format__': <built-in method __format__ of Unpicklable object at 0x10a37b350>, '__getattribute__': <method-wrapper '__getattribute__' of Unpicklable object at 0x10a37b350>, '__delattr__': <method-wrapper '__delattr__' of Unpicklable object at 0x10a37b350>, 'breakme': <bound method Unpicklable.breakme of <__main__.Unpicklable object at 0x10a37b350>>, '__repr__': <method-wrapper '__repr__' of Unpicklable object at 0x10a37b350>, '__dict__': {'x': <setiterator object at 0x10a370820>}, 'x': <setiterator object at 0x10a370820>, '__sizeof__': <built-in method __sizeof__ of Unpicklable object at 0x10a37b350>, '__init__': <method-wrapper '__init__' of Unpicklable object at 0x10a37b350>}
>>> dill.detect.badtypes(u, depth=1)
{'__hash__': <type 'method-wrapper'>, '__setattr__': <type 'method-wrapper'>, '__reduce_ex__': <type 'builtin_function_or_method'>, '__reduce__': <type 'builtin_function_or_method'>, '__str__': <type 'method-wrapper'>, '__format__': <type 'builtin_function_or_method'>, '__getattribute__': <type 'method-wrapper'>, '__delattr__': <type 'method-wrapper'>, 'breakme': <type 'instancemethod'>, '__repr__': <type 'method-wrapper'>, '__dict__': <type 'dict'>, 'x': <type 'setiterator'>, '__sizeof__': <type 'builtin_function_or_method'>, '__init__': <type 'method-wrapper'>}
>>> set(dill.detect.badtypes(u, depth=1).values())
set([<type 'dict'>, <type 'method-wrapper'>, <type 'instancemethod'>, <type 'setiterator'>, <type 'builtin_function_or_method'>])