2009-02-20 5 views
30

あなたはそれのような一般的なエラーメッセージで失敗します漬けすることはできませんいくつかの属性を持つオブジェクトpickle化する場合:どのオブジェクト属性がpickleに失敗するかを調べる方法は?

PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed 

を例外の原因となった属性伝える方法はありますか?私はPython 2.5.2を使用しています。

原則として問題の根本原因を理解していますが(例えば上記の例ではインスタンスメソッドを使用しています)、は正確にそれを特定するのが難しい場合があります。私の場合は、すでにカスタムの__getstate__メソッドを定義していましたが、重要な属性は忘れていました。これはネストされたオブジェクトの複雑な構造で起こったので、悪い属性を特定するのにはしばらく時間がかかりました。

要求されたとして、ここでは簡単な一例では、漬物が意図的に失敗した次のとおりです。

import cPickle as pickle 
import new 

class Test(object): 
    pass 

def test_func(self): 
    pass 

test = Test() 
pickle.dumps(test) 
print "now with instancemethod..." 
test.test_meth = new.instancemethod(test_func, test) 
pickle.dumps(test) 

これが出力されます。

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 

は残念ながら属性test_methが問題になることはヒントはありません。

+0

あなたは多分失敗属性の小さな例を与えることができますか?またはpickleモジュールのどこが失敗するかを見るために少なくともトレースバックを表示してください。 – MrTopf

+0

ああ、どのPythonバージョンを使用していますか? – MrTopf

+0

@MrTopf:情報 – nikow

答えて

14

もっと役に立つエラーメッセージを含まないようにPythonにバグを報告することができます。それまでの間に、copy_reg.py_reduce_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 
+3

なぜ単に印刷の代わりにエラーメッセージに "self"を入れないのですか? – MrTopf

+1

この例では "TypeError"例外が含まれていると思われますが、元の "PicklingError"例外は処理されません。 – cmcginty

+0

TypeErrorによってPicklingErrorが発生します。 instanceMethodオブジェクト(または他のピクル不可能なオブジェクト)をピクルしようとするのを止めると、すべてがうまくいくはずです。 – joeforker

8

私はあなたと同じ問題を抱えていたが、私のクラスは(すなわち類似したオブジェクトの大きな木)少し複雑だったので、印刷はあまりそれほど助けにはなりませんでした私は一緒にヘルパー機能をハッキングしました。これは完全ではなく、酸洗いプロトコル2との使用のみを目的としています。 私は自分の問題を特定できるほど十分でした。すべてをカバーするように拡張したいのであれば、プロトコルはhttp://www.python.org/dev/peps/pep-0307/で記述されています。誰もがコードを更新できるようにこの投稿を編集可能にしました。

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これはattibute K._genがpickle化可能なされていないことを意味し、同じK._base._gensために行く

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

を酸洗いしないオブジェクトである使用例。

+0

ありがとうございます。そして、私は '__getstate __()'は対応するクラスで定義されるべきだと思います。 –

3

私はあなたがPicklerさんのサブクラスを作成し、ブロックを除いて、試しにPickler.save()メソッドをラップした場合、あなたがdillを使用している場合

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) 
+0

デバッガを起動していませんか? Eclipse PyDevデバッガを使用して問題を確認するなどの違いはありますか? – nikow

+0

PyDevデバッガが例外で起動し、適切なレベルの実行に移る場合は同じです。私はIDEを使用しません。 –

+0

私はこれを使用して、見つけにくいPickleエラーを特定しました。しかし、except節がデバッガを起動するのではなく、objを出力して例外を発生させただけです。次に、MyPickler(出力).dump(obj)を実行すると、深くネストされた構造の中で、unpickleableオブジェクトがどこにあるのかという正確なトレースバックのようなレポートが得られました。何日。 – partofthething

2

ようにそれを呼び出すことを発見しましたあなたの例は、漬けに失敗しません...

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

私たちは何かを見つける必要があります帽子dillは漬けません...

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

エラーメッセージが良くなかった場合、私はトップレベルのオブジェクトが含まれているunpickle不可能なものをオブジェクト参照する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それが存在する場合は、多分、それはそれを利用する必要がありますが、__getstate__方法が存在しているに依存しません。 objgraphを使用して、ピクルしないものを構築するために使用されるすべてのオブジェクト依存関係の図を取得することもできます。上記の情報に基づいて、問題の根本原因を整理するのに役立ちます。

は、この問題ではunpickle不可能なアイテムを追跡するのにdill.detect使用を参照してください:https://github.com/uqfoundation/dill/issues/58