2012-02-16 25 views
9

Tôi có một mô-đun mở rộng cho Python sử dụng SWIG như là một wrapper và tôi cố gắng serialize nó với Pickle và tôi thất bại =)Làm thế nào để mô-đun mở rộng SWIG của tôi hoạt động với Pickle?

  1. Nếu ai có một nguồn SWIG phần mở rộng có thể được ngâm, rất thích nhìn thấy nó!
  2. Có vẻ như tôi nên triển khai phương thức __reduce_ex__ trong mã C++ của mình. Có ai có ví dụ về __reduce_ex__? There is similar Stackoverflow question nhưng nó bỏ qua thông số và thực thi manager_constructor.

Trả lời

11

Có vẻ như tôi tìm thấy giải pháp simlple mà làm việc cho tôi:

Vì vậy, chúng ta hãy nói rằng chúng ta có lớp C đã được tạo ra với SWIG, sau đó chúng tôi quấn nó với

class PickalableC(C, PickalableSWIG): 

    def __init__(self, *args): 
     self.args = args 
     C.__init__(self) 

nơi PickalableSWIG

class PickalableSWIG: 

    def __setstate__(self, state): 
     self.__init__(*state['args']) 

    def __getstate__(self): 
     return {'args': self.args} 

Sau đó

pickle.loads(pickle.dumps(C())) 

thất bại, nhưng

pickle.loads(pickle.dumps(PickalableC())) 

thành công =)

+0

Và có lẽ metaclass thể được sử dụng đây. – alexanderkuk

+0

Trong trường hợp một người quan tâm đến việc đánh giá song song với mpi4py, tôi cần bổ sung để thực hiện giải pháp được đề xuất [ở đây] (http://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-pythons- multiprocessing-pool-ma) để làm cho nó hoạt động với các phương thức ví dụ của lớp (bọc) lớp –

+0

@FredSchoen: bộ nối tiếp 'dill' có thể được sử dụng với' mpi4py'. Chỉ cần đặt bộ nối tiếp thành 'dill' thay vì' pickle'. Xem: http://stackoverflow.com/questions/21779541/mpi4py-replace-built-in-serialization –

3

Dưới đây là một vài phương pháp bổ sung. Không có khả năng ứng dụng chung như accepted answer, nhưng nếu lớp của bạn đáp ứng một số yêu cầu (đơn giản) thì bạn có thể làm cho người dùng dễ dàng hơn bằng cách tự tạo các phiên bản (không được gói phiên bản). Các kỹ thuật này đều được sử dụng bởi LSST afw package.

Lưu ý rằng khi unpickling sử dụng cặp __getstate__/__setstate__, phương pháp __init__ sẽ không được gọi, có nghĩa là trừ khi bạn cẩn thận, bạn sẽ có một đối tượng mà bạn không thể làm bất cứ điều gì với (nếu bạn tiếp tục nhận được NotImplementedError: Wrong number or type of arguments for overloaded function, đây là một khả năng). Điều này khiến chúng tôi sử dụng __reduce__ (hoặc bạn có thể gọi __init__ từ __setstate__).

Nếu bạn SWIG-ing lớp Foo mà lấy đối số nhà xây dựng mà bạn có thể truy cập từ các trường hợp (ví dụ, thông qua accessors), thêm dòng sau vào giao diện của bạn (.i) file:

%extend Foo { 
%pythoncode { 
    def __reduce__(self): 
     # Requires matching constructor: __init__(foo, bar) 
     args = self.getFoo(), self.getBar() 
     return self.__class__, args 
} 
} 

Nếu bạn có thể tạo đối tượng của bạn với một constructor mặc định và sau đó vận dụng nó để lấy lại trạng thái trước đây của nó, sử dụng một cái gì đó như thế này:

%extend Foo { 
%pythoncode { 
    def __getstate__(self): 
     args = self.getFoo(), self.getBar() 
     return args 
    def __setstate__(self, state): 
     # Requires empty constructor: __init__() 
     self.__init__() 
     foo, bar = state 
     self.setFoo(foo) 
     self.setBar(bar) 
} 
} 

Ngoài ra, nếu lớp học của bạn có thể làm một serialization dữ liệu nhị phân đến/từ bộ nhớ (ví dụ ., Một số đại diện trong bộ nhớ định dạng trên đĩa của bạn):

%include "cdata.i" 

%extend Foo { 
%pythoncode { 
    def __reduce__(self): 
     s = Serializer() 
     self.serialize(s) 
     size = s.getLength() 
     data = cdata(s.getData(), size) 
     return unreduceFoo, (data, size) 
} 
} 

%pythoncode { 
def unreduceFoo(data, size): 
    s = Serializer(size) 
    memmove(s.getData(), data) 
    return Foo(s) 
} 

Cuối cùng, nếu bạn đang sử dụng boost::serialization, sử dụng đoạn mã này bằng cách Sogo Mineo:

%{ 
    #include <boost/serialization/serialization.hpp> 
    #include <boost/archive/binary_oarchive.hpp> 
    #include <boost/archive/binary_iarchive.hpp> 
    #include <sstream> 
%} 
%include "std_string.i" 

%define %boost_picklable(cls...) 
    %extend cls { 
     std::string __getstate__() 
     { 
      std::stringstream ss; 
      boost::archive::binary_oarchive ar(ss); 
      ar << *($self); 
      return ss.str(); 
     } 

     void __setstate_internal(std::string const& sState) 
     { 
      std::stringstream ss(sState); 
      boost::archive::binary_iarchive ar(ss); 
      ar >> *($self); 
     } 

     %pythoncode %{ 
      def __setstate__(self, sState): 
       self.__init__() 
       self.__setstate_internal(sState) 
     %} 
    } 
%enddef 

%boost_picklable(Foo) 
Các vấn đề liên quan