2009-02-20 32 views
30

Khi bạn dưa một đối tượng mà có một số thuộc tính mà không thể được ngâm nó sẽ thất bại với một thông báo lỗi chung chung như:Làm cách nào để biết đối tượng thuộc tính nào không hoạt động?

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

Có cách nào để cho các thuộc tính gây ra ngoại lệ? Tôi đang sử dụng Python 2.5.2.

Mặc dù tôi hiểu nguyên tắc gốc nguyên nhân của vấn đề (ví dụ trong ví dụ trên có phương pháp thể hiện) nhưng vẫn có thể rất khó để xác định chính xác số. Trong trường hợp của tôi, tôi đã định nghĩa phương thức __getstate__ tùy chỉnh, nhưng đã quên một thuộc tính quan trọng. Điều này xảy ra trong một cấu trúc phức tạp của các đối tượng lồng nhau, vì vậy nó đã cho tôi một thời gian để xác định các thuộc tính xấu.

Theo yêu cầu, đây là một ví dụ đơn giản là dưa cố ý không:

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) 

Đây là kết quả:

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 

Đáng tiếc là không có gợi ý rằng thuộc tính test_meth gây ra vấn đề.

+0

bạn có thể có thể cung cấp cho một ví dụ nhỏ của một thuộc tính không? hoặc ít nhất là hiển thị thêm một chút về truy nguyên để xem vị trí trong mô-đun dưa không thành công? – MrTopf

+0

oh và bạn đang sử dụng phiên bản Python nào? – MrTopf

+0

@MrTopf: đã thêm thông tin – nikow

Trả lời

14

Bạn có thể gửi lỗi chống lại Python vì không bao gồm các thông báo lỗi hữu ích hơn. Trong thời gian chờ đợi, hãy sửa đổi chức năng _reduce_ex() trong copy_reg.py.

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

Output:

<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

tại sao không chỉ đơn giản là đặt "tự" vào thông báo lỗi thay vì in? – MrTopf

+1

Tôi tin rằng điều này bao gồm ngoại lệ "TypeError" trong ví dụ, tuy nhiên ngoại lệ "PicklingError" ban đầu không được giải quyết. – cmcginty

+0

Loại lỗi gây ra PicklingError. Một khi bạn ngừng cố gắng để chọn đối tượng instancemethod (hoặc bất kỳ đối tượng không thể chọn khác) tất cả mọi thứ sẽ làm việc. – joeforker

8

tôi đã có vấn đề tương tự như bạn, nhưng lớp học của tôi là một chút phức tạp hơn (tức là một cái cây lớn các đối tượng tương tự) nên việc in ấn không giúp nhiều đến nỗi Tôi đã hack cùng một chức năng trợ giúp. Nó không đầy đủ và chỉ được sử dụng với giao thức tẩy 2: Đủ để tôi có thể xác định được vấn đề của tôi. Nếu bạn muốn mở rộng nó để trang trải mọi thứ, giao thức được mô tả tại http://www.python.org/dev/peps/pep-0307/ tôi đã làm cho bài đăng này có thể chỉnh sửa để mọi người có thể cập nhật mã.

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 

Một ví dụ về việc sử dụng đó K là đối tượng mà không dưa

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

Điều này có nghĩa rằng attibute K._gen không picklable và cùng đi cho K._base._gens .

+0

Cảm ơn, nó giúp. Và tôi nghĩ '__getstate __()' nên được định nghĩa trong lớp tương ứng. –

3

Tôi đã tìm thấy rằng nếu bạn phân lớp Pickler và quấn phương pháp Pickler.save() trong một thử, trừ khối

import pickle 
class MyPickler (pickle.Pickler): 
    def save(self, obj): 
     try: 
      pickle.Pickler.save(self, obj) 
     except Exception, e: 
      import pdb;pdb.set_trace() 

Sau đó gọi nó như vậy

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

Đây không phải là chỉ bắt đầu một trình gỡ rối? Có sự khác biệt nào không, ví dụ: chỉ cần sử dụng Trình gỡ lỗi PyDev Eclipse để xem xét vấn đề? – nikow

+0

Nếu trình gỡ lỗi PyDev sẽ khởi động ngoại lệ và đưa bạn vào đúng mức thực thi, nó giống nhau. Tôi không sử dụng một IDE mặc dù. –

+0

Tôi đã sử dụng tính năng này để xác định lỗi Pickle đặc biệt khó tìm. Nhưng thay vì có mệnh đề except bắt đầu trình gỡ lỗi, tôi chỉ có nó in obj và tăng ngoại lệ. Sau đó, chạy MyPickler (đầu ra) .dump (obj) dẫn đến một báo cáo traceback giống như chính xác về nơi mà đối tượng không thể nhấp được nằm trong các cấu trúc lồng nhau của tôi. Thật là một ngày. – partofthething

2

Nếu bạn sử dụng dill , ví dụ của bạn không thất bại trong việc chọn lựa ...

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

Vì vậy, chúng tôi phải tìm một thứ gì đó t mũ dill không thể dưa ...

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

Nếu thông báo lỗi không tốt, tôi có thể sử dụng dill.detect để xem đối tượng cấp cao nào chứa đối tượng cấp cao nhất.

>>> 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 không dựa trên __getstate__ phương pháp có mặt, mặc dù có thể nó sẽ sử dụng nó nếu nó tồn tại. Bạn cũng có thể sử dụng objgraph để có được một hình ảnh của tất cả các phụ thuộc đối tượng được sử dụng để xây dựng những điều mà không dưa. Nó có thể giúp bạn phân loại gốc rễ của vấn đề là gì, dựa trên thông tin trên.

Xem dill.detect sử dụng trong việc theo dõi mục unpicklable trong vấn đề này: https://github.com/uqfoundation/dill/issues/58

Các vấn đề liên quan