2010-02-05 38 views
24

Tôi đang cố gắng chọn một đối tượng của một lớp (kiểu mới) mà tôi đã xác định. Nhưng tôi nhận được lỗi sau:Tại sao tôi nhận được lỗi về lớp học của tôi xác định __slots__ khi cố gắng chọn một đối tượng?

>>> with open('temp/connection.pickle','w') as f: 
... pickle.dump(c,f) 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "/usr/lib/python2.5/pickle.py", line 1362, in dump 
    Pickler(file, protocol).dump(obj) 
    File "/usr/lib/python2.5/pickle.py", line 224, in dump 
    self.save(obj) 
    File "/usr/lib/python2.5/pickle.py", line 331, in save 
    self.save_reduce(obj=obj, *rv) 
    File "/usr/lib/python2.5/pickle.py", line 419, in save_reduce 
    save(state) 
    File "/usr/lib/python2.5/pickle.py", line 286, in save 
    f(self, obj) # Call unbound method with explicit self 
    File "/usr/lib/python2.5/pickle.py", line 649, in save_dict 
    self._batch_setitems(obj.iteritems()) 
    File "/usr/lib/python2.5/pickle.py", line 663, in _batch_setitems 
    save(v) 
    File "/usr/lib/python2.5/pickle.py", line 306, in save 
    rv = reduce(self.proto) 
    File "/usr/lib/python2.5/copy_reg.py", line 76, in _reduce_ex 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 

Tôi không xác định rõ ràng __slots__ trong lớp học của mình. Có phải tôi đã định nghĩa điều gì đó không? Tôi làm cách nào để giải quyết vấn đề này? Tôi có cần xác định __getstate__ không?

Cập nhật:gnibbler chọn ví dụ điển hình. Lớp của đối tượng tôi đang cố gắng để kết thúc tốt đẹp một ổ cắm. (Nó xảy ra với tôi bây giờ mà) ổ cắm xác định __slots__ và không __getstate__ vì lý do chính đáng. Tôi giả sử một khi một quá trình kết thúc, một quá trình khác không thể tháo bỏ và sử dụng kết nối socket của quá trình trước đó. Vì vậy, trong khi tôi chấp nhận câu trả lời tuyệt vời của Alex Martelli, tôi sẽ phải theo đuổi một chiến lược khác hơn là chọn "chia sẻ" đối tượng tham chiếu.

+1

Bạn có thể hiển thị một số mã từ lớp học không? Có lẽ chúng ta không cần phải xem * tất cả * các phương pháp. –

Trả lời

26

Lớp xác định __slots__ (và không __getstate__) có thể là lớp tổ tiên của bạn hoặc lớp (hoặc lớp tổ tiên) của thuộc tính hoặc mục của bạn, trực tiếp hoặc gián tiếp: về cơ bản, lớp của bất kỳ đối tượng nào trong các đồ thị được hướng dẫn được hướng dẫn với đối tượng của bạn dưới dạng gốc, vì việc chọn lọc cần lưu toàn bộ biểu đồ.

Một giải pháp đơn giản cho tình trạng khó khăn của bạn là sử dụng giao thức -1, có nghĩa là "giao thức tốt nhất có thể sử dụng"; mặc định là giao thức dựa trên ASCII cổ đại, áp đặt giới hạn này về __slots__ so với __getstate__. Xem xét:

>>> class sic(object): 
... __slots__ = 'a', 'b' 
... 
>>> import pickle 
>>> pickle.dumps(sic(), -1) 
'\x80\x02c__main__\nsic\nq\x00)\x81q\x01.' 
>>> pickle.dumps(sic()) 
Traceback (most recent call last): 
    [snip snip] 
    raise TypeError("a class that defines __slots__ without " 
TypeError: a class that defines __slots__ without defining __getstate__ cannot be pickled 
>>> 

Như bạn thấy, giao thức -1 lấy __slots__ trong sải chân, trong khi giao thức mặc định cung cấp cho các ngoại lệ tương tự như bạn đã thấy.

Các vấn đề với giao thức -1: nó tạo chuỗi nhị phân/tệp, chứ không phải mã ASCII giống như giao thức mặc định; tập tin được tạo ra sẽ không thể tải được bởi các phiên bản Python đầy đủ. Ưu điểm, bên cạnh chìa khóa một wrt __slots__, bao gồm kết quả nhỏ gọn hơn, và hiệu suất tốt hơn.

Nếu bạn buộc phải sử dụng giao thức mặc định, bạn sẽ cần phải xác định chính xác lớp nào đang gây ra sự cố và chính xác lý do. Chúng ta có thể thảo luận về chiến lược nếu đây là trường hợp (nhưng nếu bạn có thể sử dụng giao thức -1, tốt hơn rất nhiều là nó không đáng để thảo luận ;-) và kiểm tra mã đơn giản để tìm lớp/đối tượng phiền phức đang tỏ ra quá phức tạp (tôi có trong tâm trí một số thủ thuật dựa trên deepcopy để có được một đại diện có thể sử dụng của toàn bộ đồ thị, trong trường hợp bạn đang tự hỏi).

2

Từ PEP 307:

The __getstate__ method should return a picklable value representing the object's state without referencing the object itself. If no __getstate__ method exists, a default implementation is used that returns self.__dict__ .

6

Có lẽ một thuộc tính của dụ bạn đang sử dụng __slots__

Ví dụ, socket__slots__ nên nó không thể được ngâm

Bạn cần phải xác định được thuộc tính đang gây ra lỗi và viết __getstate____setstate__ của riêng bạn để bỏ qua thuộc tính đó

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