2012-02-16 7 views
9

tengo un módulo de extensión de Python que utiliza el TRAGO como envoltorio y trato de serializarlo con salmuera y fallar =)¿Cómo hacer que mi módulo de extensión SWIG funcione con Pickle?

  1. Si alguien tiene una fuente de extensión TRAGO que puede ser en escabeche, me encantaría ¡Míralo!
  2. Parece que debería implementar el método __reduce_ex__ en mi código C++. ¿Alguien tiene un ejemplo de __reduce_ex__? There is similar Stackoverflow question pero omite la especificación e implementación de manager_constructor.

Respuesta

11

parece que he encontrado la solución simlple que funciona para mí:

Así que vamos a decir que tenemos la clase C que se generó con el TRAGO, luego se envuelve con

class PickalableC(C, PickalableSWIG): 

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

donde PickalableSWIG es

class PickalableSWIG: 

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

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

Entonces

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

falla, pero

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

tiene éxito =)

+0

Y tal metaclase se puede utilizar aquí. – alexanderkuk

+0

En caso de que uno esté interesado en la evaluación paralela con mpi4py, necesitaba implementar adicionalmente la solución sugerida [aquí] (http://stackoverflow.com/questions/1816958/cant-pickle-type-instancemethod-when-using-pythons- multiprocesamiento-pool-ma) para hacer que funcione con los métodos de instancia de la clase (envuelta) –

+0

@FredSchoen: el serializador 'eneldo' se puede usar con' mpi4py'. Simplemente configure el serializador para 'eneldo' en lugar de 'salmuera'. Ver: http://stackoverflow.com/questions/21779541/mpi4py-replace-built-in-serialization –

3

Éstos son algunos métodos adicionales. Ninguno tiene una aplicabilidad tan general como el accepted answer, pero si su clase cumple con algunos requisitos (simples), entonces puede facilitar el decapado a sus usuarios haciendo que las instancias mismas (no versiones envueltas) se puedan seleccionar. Estas técnicas son todas usadas por el LSST afw package.

Tenga en cuenta que cuando deserialiación utilizando el par __getstate__/__setstate__, el método __init__ se no ser llamado, lo que significa que a menos que usted tiene cuidado, usted tiene un objeto que no se puede hacer nada con (si sigues recibiendo NotImplementedError: Wrong number or type of arguments for overloaded function, esta es una posibilidad). Esto nos lleva a utilizar __reduce__ (o puede llamar al __init__ desde __setstate__).

Si eres de clase TRAGO-ción Foo que tiene argumentos de constructor que tiene acceso a partir de la instancia (por ejemplo, a través de descriptores de acceso), añada lo siguiente a su interfaz (.i) Archivo:

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

Si usted puede crear su objeto con un constructor por defecto y luego manipularla para recuperar su estado anterior, usar algo como esto:

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

Alternativamente, si la clase puede hacer una serialización de datos binarios a/desde la memoria (por ejemplo, ., Alguna representación en memoria de su propio formato en 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) 
} 

Por último, si usted está utilizando boost::serialization, utilice este fragmento por 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) 
Cuestiones relacionadas