2012-02-16 15 views
9

ho un modulo di estensione per Python che usa SWIG come wrapper e cerco di serializzare con sottaceto e io non riuscire =)Come far funzionare il mio modulo di estensione SWIG con Pickle?

  1. Se qualcuno ha una fonte di estensione SWIG che possono essere in salamoia, mi piacerebbe Guardalo!
  2. Sembra che dovrei implementare il metodo __reduce_ex__ nel mio codice C++. Qualcuno ha un esempio di __reduce_ex__? There is similar Stackoverflow question ma omette la specifica e l'implementazione manager_constructor.

risposta

11

Sembra come ho trovato la soluzione simlple che funziona per me:

Quindi cerchiamo di dire che abbiamo classe C che è stato generato con SWIG, poi avvolgerla con

class PickalableC(C, PickalableSWIG): 

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

dove PickalableSWIG è

class PickalableSWIG: 

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

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

Poi

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

fallisce, ma

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

riesce =)

+0

E forse metaclasse può essere utilizzato Qui. – alexanderkuk

+0

Nel caso si sia interessati alla valutazione parallela con mpi4py, avevo bisogno di implementare ulteriormente la soluzione suggerita [qui] (http://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-pythons- multiprocessing-pool-ma) per farlo funzionare con i metodi di istanza della classe (wrapping) –

+0

@FredSchoen: il serializzatore 'dill' può essere utilizzato con' mpi4py'. Basta impostare il serializzatore su 'dill' invece di' pickle'. Vedi: http://stackoverflow.com/questions/21779541/mpi4py-replace-built-in-serialization –

3

Ecco alcuni metodi aggiuntivi. Nessuna è di applicabilità generale come lo è accepted answer, ma se la classe soddisfa alcuni (semplici) requisiti, è possibile rendere più facile il decapaggio sui propri utenti rendendo selezionabili le istanze stesse (non le versioni avvolte). Queste tecniche sono tutte utilizzate dallo LSST afw package.

noti che quando deserializzazione utilizzando la coppia __getstate__/__setstate__, sarà non essere chiamato il metodo __init__, il che significa che se non si sta attenti, avrete un oggetto che non si può fare nulla con (se continui a ricevere NotImplementedError: Wrong number or type of arguments for overloaded function, questa è una possibilità). Questo ci spinge a usare __reduce__ (o è possibile chiamare __init__ da __setstate__).

Se siete classe SWIG-ing Foo che prende argomenti del costruttore che si ha accesso dall'istanza (ad esempio, via di accesso), aggiungere il seguente alla vostra interfaccia (.i) File:

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

Se è possibile creare il vostro oggetto con un costruttore di default e poi manipolarlo per ritrovare il suo stato precedente, usare qualcosa di simile a questo:

%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) 
} 
} 

in alternativa, se la classe può fare una serializzazione dei dati binari a/dalla memoria (ad esempio, ., Qualche rappresentazione in memoria del proprio formato su disco):

%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) 
} 

Infine, se si sta utilizzando boost::serialization, utilizzare questo frammento da 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) 
Problemi correlati