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