python pickle slots

python - ¿Por qué recibo un error sobre mi clase que define__slots__ cuando intento encurtir un objeto?



pickle (3)

De la PEP 307 :

El método __getstate__ debe devolver un valor seleccionable que represente el estado del objeto sin hacer referencia al objeto en sí. Si no existe el método __getstate__ , se usa una implementación predeterminada que devuelve self.__dict__ .

Estoy tratando de encurtir un objeto de una clase (estilo nuevo) que definí. Pero estoy recibiendo el siguiente error:

>>> 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

No __slots__ explícitamente __slots__ en mi clase. ¿Algo que hice lo definí implícitamente? ¿Cómo trabajo alrededor de esto? ¿Necesito definir __getstate__ ?

Actualización: gnibbler eligió un buen ejemplo. La clase del objeto que estoy tratando de encurtir envuelve un socket. (Se me ocurre ahora que) los sockets definen __slots__ y no __getstate__ por una buena razón. Supongo que una vez que finaliza un proceso, otro proceso no puede deshacerse y usar la conexión de socket del proceso anterior. Entonces, si bien estoy aceptando la excelente respuesta de Alex Martelli , tendré que seguir una estrategia diferente a la de "compartir" la referencia del objeto.


La clase que define __slots__ (y no __getstate__ ) puede ser una clase ancestral tuya, o una clase (o clase antecesora) de un atributo o elemento tuyo, directa o indirectamente: esencialmente, la clase de cualquier objeto en el gráfico dirigido de referencias con su objeto como raíz, ya que el decapado debe guardar el gráfico completo.

Una solución simple para su dilema es usar el protocolo -1 , que significa "el mejor protocolo que puede usar"; el valor predeterminado es un antiguo protocolo basado en ASCII que impone esta limitación sobre __slots__ vs __getstate__ . Considerar:

>>> 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 >>>

Como ve, el protocolo -1 toma las __slots__ con calma, mientras que el protocolo predeterminado le da la misma excepción que vio.

Los problemas con el protocolo -1 : produce una cadena / archivo binario, en lugar de uno ASCII como el protocolo predeterminado; el archivo decapado resultante no se podría cargar con versiones suficientemente antiguas de Python. Las ventajas, además de la clave one wrt __slots__ , incluyen resultados más compactos y mejor rendimiento.

Si se ve obligado a usar el protocolo predeterminado, deberá identificar exactamente qué clase le está causando problemas y exactamente por qué. Podemos discutir estrategias si este es el caso (pero si es posible que pueda usar el protocolo -1 , eso es mucho mejor que no vale la pena discutirlo ;-) y la simple inspección de código en busca de la clase problemática / objeto está resultando demasiado complicada (I tenga en mente algunos trucos basados ​​en copia profunda para obtener una representación útil de todo el gráfico, en caso de que se lo pregunte).


Quizás un atributo de tu instancia esté usando __slots__

Por ejemplo, socket tiene __slots__ por lo que no puede ser decapado

__getstate__ identificar qué atributo está causando el error y escribir su propio __getstate__ y __setstate__ para ignorar ese atributo