2011-07-05 16 views
5

phương pháp sơ thẩm có thể không tự động được ngâm trong cả hai Python 2 hoặc Python 3.Đây có phải là cách đúng để chọn các phương pháp mẫu không? Nếu có, tại sao không phải là nó trong Python 3?

tôi cần phải dưa phương pháp dụ với Python 3 và tôi chuyển mã ví dụ của Steven Bethard để Python 3:

import copyreg 
import types 

def _pickle_method(method): 
    func_name = method.__func__.__name__ 
    obj = method.__self__ 
    cls = method.__self__.__class__ 
    return _unpickle_method, (func_name, obj, cls) 

def _unpickle_method(func_name, obj, cls): 
    for cls in cls.mro(): 
     try: 
      func = cls.__dict__[func_name] 
     except KeyError: 
      pass 
     else: 
      break 
    return func.__get__(obj, cls) 

copyreg.pickle(types.MethodType, _pickle_method, _unpickle_method) 

Đây có phải là phương pháp đánh lừa bằng chứng cho phương pháp tẩy dụ? Hoặc có thể một số điều sai lầm khủng khiếp? Tôi đã thử nghiệm nó với một số giả lập các lớp học và tất cả mọi thứ dường như làm việc.

Nếu không có gì có thể xảy ra sai, tại sao không thể thực hiện được trong Python 3 cho các phương pháp lấy mẫu tiêu chuẩn?

+0

Bởi vì tất cả tài liệu tham khảo phải được truy cập trên toàn cầu. http://www.velocityreviews.com/forums/t395502-why-cant-you-pickle-instancemethods.html –

+0

@Lennart Nếu bạn nhìn vào liên kết, bạn sẽ thấy rằng tôi đã tìm thấy chính chuỗi đó. Tuy nhiên nó không giải thích rõ sự khác biệt thực sự giữa việc chọn phương thức và hàm. Tôi biết rằng cũng có một số chức năng, giống như một hàm lambda không thể được ngâm, nhưng trong trường hợp đó một lỗi được ném ra khi nó là không thể. Tại sao không giống nhau cho các phương pháp? –

Trả lời

0

Tôi thực sự không thể tạo lại vấn đề gốc trên trăn 3.5.0, xem ví dụ sau. Nó có thể là giá trị kiểm tra trên phiên bản mới nhất để xem nếu nó chỉ hoạt động out-of-the-box :-)

import pickle 
import sys 

class Foo: 

    @staticmethod 
    def my_func(): 
     return 'Foo.my_func' 


class Bar: 
    pass 

if __name__ == '__main__': 
    if len(sys.argv) > 1 and sys.argv[1] == 'restore': 
     print('loading pickle') 
     with open('test.pickle', 'rb') as fp: 
      restored = pickle.load(fp) 
      print(restored.baz()) 
    else: 
     print('saving pickle') 
     b = Bar() 
     b.baz = Foo.my_func 

     with open('test.pickle', 'w+b') as fp: 
      p = pickle.dump(b, fp) 

(thử nghiệm) ~/kiểm tra $ python test.py

tiết kiệm dưa

(thử nghiệm) ~/kiểm tra $ python test.py khôi phục

tải dưa

Foo.my_func

0

Nếu bạn muốn dưa trường lớp (và các phương pháp chẳng hạn), chỉ cần sử dụng dill ...

>>> import dill 
>>> 
>>> class Foo: 
... def bar(self, x): 
...  return self.y + x 
... def zap(self, y): 
...  self.y = y 
... y = 1 
... 
>>> f = Foo() 
>>> f.zap(4) 
>>> f.monty = 'python' 
>>> 
>>> _f = dill.dumps(f) 
>>> del Foo 
>>> del f 
>>> f = dill.loads(_f) 
>>> f.monty 
'python' 
>>> f.y 
4 
>>> 
>>> _b = dill.dumps(f.bar) 
>>> del f 
>>> bar = dill.loads(_b) 
>>> bar(4) 
8 
>>> 

dill hoạt động khi bạn xóa các đối tượng lớp, như đã thấy ở trên ... do đó, nó cũng hoạt động nếu bạn bắt đầu một phiên python tươi mà không có lớp được xác định, hoặc nếu bạn thay đổi định nghĩa lớp. dill thậm chí hoạt động khi bạn không có một thể hiện của đối tượng lớp hoặc một cá thể lớp có sẵn. Nếu bạn muốn xem làm thế nào để làm điều đó, hãy nhìn vào mã dill nguồn: https://github.com/uqfoundation/dill

Cũng thấy có liên quan: https://stackoverflow.com/a/21345273/2379433