2009-02-20 6 views
30

Wenn Sie ein Objekt Beize, die einige Eigenschaften hat, die es mit einer allgemeinen Fehlermeldung wie fehlschlagen werden kann, nicht gebeizt:Wie erkennt man, für welches Objekt-Attribut ein Beizen fehlschlägt?

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

Gibt es eine Möglichkeit, das Attribut zu sagen, die Ausnahme verursacht? Ich benutze Python 2.5.2.

Obwohl ich im Prinzip die Ursache des Problems verstehe (z. B. im obigen Beispiel mit einer Instanzmethode), kann es immer noch sehr schwierig sein, genau zu lokalisieren. In meinem Fall habe ich bereits eine benutzerdefinierte __getstate__ Methode definiert, aber ein kritisches Attribut vergessen. Dies geschah in einer komplizierten Struktur verschachtelter Objekte, daher brauchte ich eine Weile, um das fehlerhafte Attribut zu identifizieren.

Wie gewünscht, hier ist ein einfaches Beispiel Gurken waren nicht absichtlich:

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) 

Dies ist die Ausgabe:

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 

Leider gibt es keinen Hinweis, dass das Attribut test_meth das Problem verursacht.

+0

können Sie vielleicht ein kleines Beispiel eines ausfall Attribut geben? oder zumindest ein bisschen mehr vom Traceback zeigen, um zu sehen, wo es im Beizmodul fehlschlägt? – MrTopf

+0

oh, und welche Python-Version verwendest du? – MrTopf

+0

@MrTopf: hinzugefügt die Informationen – nikow

Antwort

14

Sie könnten einen Fehler gegen Python einreichen, der keine hilfreicheren Fehlermeldungen enthält. Ändern Sie in der Zwischenzeit die _reduce_ex()-Funktion in copy_reg.py.

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

Ausgang:

<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

warum nicht einfach "self" in die Fehlermeldung anstatt des Drucks? – MrTopf

+1

Ich glaube, dass dies die "TypeError" Ausnahme im Beispiel abdeckt, aber die ursprüngliche "PicklingError" Ausnahme ist nicht adressiert. – cmcginty

+0

Der TypeError verursacht den PicklingError. Sobald Sie aufhören zu versuchen, instancemethod Objekte (oder andere nicht pickleable-Objekt) pickle alles sollte funktionieren. – joeforker

8

hatte ich das gleiche Problem wie du, aber meine Klassen waren etwas komplizierter (dh ein großer Baum ähnlicher Objekte), so dass der Druck half nicht viel, so Ich habe eine Hilfsfunktion zusammengehackt. Es ist nicht vollständig und ist nur für den Einsatz mit Beizprotokoll 2: Es war genug, damit ich meine Probleme finden konnte. Wenn Sie es um alles erweitern möchten, ist das Protokoll beschrieben unter http://www.python.org/dev/peps/pep-0307/ Ich habe diesen Beitrag editierbar gemacht, damit jeder den Code aktualisieren kann.

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 

Ein Beispiel für die Verwendung, wobei K das Objekt ist, das nicht

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

nicht beizen Dies bedeutet, dass die attibute K._gen nicht ist picklable und das gleiche gilt für K._base._gens .

+0

Danke, es hilft. Und ich denke "__getstate __()" sollte in der entsprechenden Klasse definiert werden. –

3

Ich habe festgestellt, dass, wenn Sie Pickler Unterklasse und wickeln Sie das Pickler.save() -Methode in einem Versuch, außer 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() 

es dann wie

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

Startet das nicht gerade einen Debugger? Gibt es einen Unterschied, wenn Sie zum Beispiel nur den Eclipse PyDev Debugger verwenden, um das Problem zu betrachten? – nikow

+0

Wenn der PyDev-Debugger mit der Ausnahme gestartet wird und Sie in die richtige Ausführungsebene versetzt, ist es identisch. Ich benutze jedoch keine IDE. –

+0

Ich habe dies verwendet, um einen besonders schwer zu findenden Pickle-Fehler zu finden. Aber anstatt die except-Klausel den Debugger starten zu lassen, hatte ich gerade den Befehl obj drucken und die Exception auslösen. Dann führte das Ausführen von MyPickler (output) .dump (obj) zu einem netten traceback-artigen Bericht, der genau angibt, wo sich das nicht entfernbare Objekt in meinen tief verschachtelten Strukturen befand. Was für ein Tag. – partofthething

2

so nennen Wenn Sie dill verwenden , Ihr Beispiel versagt nicht zu beizen ...

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

So müssen wir etwas t finden Hut dill kann nicht beizen ...

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

Wenn die Fehlermeldung enthält nicht gut, war, konnte ich dill.detect zu sehen, benutzen das, was unpicklable Objekte das Objekt der obersten Ebene.

>>> 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 beruht nicht auf dem __getstate__ Verfahren vorhanden ist, obwohl vielleicht sollte es es nutzen, wenn es vorhanden ist. Sie können auch objgraph verwenden, um ein Bild von allen Objektabhängigkeiten zu erhalten, die verwendet werden, um die Sache zu erstellen, die nicht pickle. Es kann Ihnen helfen, basierend auf den oben genannten Informationen herauszufinden, was der Grund des Problems ist.

Siehe dill.detect Verwendung in unpicklable Artikel in dieser Ausgabe aufzuspüren: https://github.com/uqfoundation/dill/issues/58