Cómo comprobar si un objeto es pickleable

Tengo una lista de objetos de varios tipos que quiero encurtir. Me gustaría encurtir sólo aquellos que son pickleable. ¿Hay una forma estándar de verificar si un objeto es de tipo pickleable, aparte de intentarlo?

La documentación dice que si se produce una excepción de decapado, es posible que ya se haya escrito algunos de los bytes en el archivo, por lo que tratar de decapar los objetos como prueba no parece una buena solución.

Vi este post pero no responde mi pregunta.

Yo propondría pruebas de pato en este caso. Intente escabullirse en un archivo temporal o en un archivo de memoria, según lo encuentre conveniente, luego, si falla, descarte el resultado, si tiene éxito, cambie el nombre.

¿Por qué?

En Python puedes verificar si el objeto tiene algunas propiedades de dos maneras.

Compruebe si el objeto es una instancia de alguna clase base abstracta . Por ejemplo, Number “La raíz de la jerarquía numérica. Si solo desea verificar si un argumento x es un número, sin importar qué tipo, use isinstance (x, Number)”.

O inténtalo y luego maneja las excepciones. Esto ocurre en muchas ocasiones. La filosofia pythonica se basa alrededor del pato . Duck typing , duck test y EAFP son las palabras clave.

Incluso creo que el primero se ha introducido correctamente con python3 bajo la presión de la parte de la comunidad, mientras que muchos todavía creen firmemente que el pato es el camino a seguir con python.

AFAIK no hay condiciones previas especiales que puedan verificarse, ni ningún ABC que se pueda verificar el objeto en caso de decapado. Así que todo lo que queda es pato .

Tal vez se podría intentar algo más, pero probablemente no valga la pena. Sería muy difícil hacer una introspección manual del objeto para averiguar preliminarmente si es adecuado para el decapado.

Existe el método dill.pickles en el paquete de dill que hace precisamente eso.

 >>> class Foo(object): ... x = iter([1,2,3]) ... >>> f = Foo() >>> >>> dill.pickles(f) False 

Podemos usar métodos en el dill para buscar qué causa la falla.

 >>> dill.detect.badtypes(f)  >>> dill.detect.badtypes(f, depth=1) {'__setattr__': , '__reduce_ex__': , '__reduce__': , '__str__': , '__format__': , '__getattribute__': , '__class__': , '__delattr__': , '__subclasshook__': , '__repr__': , '__hash__': , 'x': , '__sizeof__': , '__init__': } >>> dill.detect.badtypes(f, depth=1).keys() ['__setattr__', '__reduce_ex__', '__reduce__', '__str__', '__format__', '__getattribute__', '__class__', '__delattr__', '__subclasshook__', '__repr__', '__hash__', 'x', '__sizeof__', '__init__'] 

Entonces, lo único que está fallando que no es un método “incorporado” de la clase es x … así que es un buen lugar para comenzar. Verifiquemos ‘x’, luego reemplazémoslo con otra cosa si es el problema.

 >>> dill.pickles(Foo.x) False >>> Foo.x = xrange(1,4) >>> dill.pickles(Foo.x) True 

Sí, x estaba causando un fallo, y reemplazarlo con un xrange funciona porque dill puede xrange un xrange . ¿Qué queda por hacer?

 >>> dill.detect.badtypes(f, depth=1).keys() [] >>> dill.detect.badtypes(f, depth=1) {} >>> dill.pickles(f) True >>> 

Aparentemente (probablemente porque las referencias a x en la clase __dict__ ahora encurtidos), f ahora encurtidos … así que hemos terminado.

dill también proporciona un trace para mostrar la ruta exacta en el decapado del objeto.

 >>> dill.detect.trace(True) >>> dill.pickles(f) T2:  F2:  T1:  F2:  T1:  D2:  Si: xrange(1, 4) F2:  D2:  True 

dill permite decapar más cosas que el pickle incorporado.

Esto debería hacer lo que tú, creo:

 def is_picklable(obj): try: pickle.dumps(obj) except pickle.PicklingError: return False return True