2012-01-23 11 views
12

Me sorprendió encontrar que python (versión 3.2.2) se negaba a recuperar un objeto porque su dict contenía una referencia a Ellipsis. Del otro built-in constants, pickle está feliz trabajando con False, True y None, como se indica explícitamente en el pickle documentation, pero también se ahoga en NotImplemented.¿Por qué no se pueden salpicar Ellipsis y NotImplemented?

Python 3.2.2 (default, Sep 5 2011, 21:17:14) 
[GCC 4.6.1] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import pickle 
>>> pickle.dumps(True) 
b'\x80\x03\x88.' 
>>> pickle.dumps(False) 
b'\x80\x03\x89.' 
>>> pickle.dumps(None) 
b'\x80\x03N.' 
>>> pickle.dumps(Ellipsis) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
_pickle.PicklingError: Can't pickle <class 'ellipsis'>: attribute lookup builtins.ellipsis failed 
>>> pickle.dumps(NotImplemented) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
_pickle.PicklingError: Can't pickle <class 'NotImplementedType'>: attribute lookup builtins.NotImplementedType failed 

Para completar, de las constantes integradas en menos útiles, __debug__ es sólo un bool, por lo que no causa ningún problema; copyright, license, y credits trabajo (su tipo es site._Printer); quit y exit no (su tipo es site.Quitter, que no se puede encontrar como se define dentro de una función).

¿Alguien puede explicar por qué esto es - seguramente Ellipsis y NotImplemented no se han pasado por alto? La única información relevante que puedo encontrar es this bug, que se queja de que NoneType (es decir, type(None)) no es seleccionable. Uno de los comentaristas menciona que type(Ellipsis) y type(NotImplemented) no pueden ser escabechados, aparentemente sin darse cuenta de que sus instancias tampoco pueden serlo.

+2

extraña omisión, aunque se podría argumentar que no se supone realmente para mantener las referencias a esos valores, para empezar. – millimoose

+0

@Inderdial: mi caso de uso particular estaba en un contenedor que realiza un seguimiento de los sectores a los que se ha accedido. Como las rebanadas pueden ser escabechadas, parece extraño que las elipsis (que en realidad son solo un tipo especial de corte) no puedan. Guardar una referencia a 'NotImplemented' probablemente sea menos útil, aunque me imagino que alguien podría quererlo por algún tipo de esquema de comparación complicado. – James

+1

@James - Estrictamente hablando, 'Ellipsis' no es un tipo especial de porción, pero su interpretación está absolutamente definida por el usuario. En Numpy, se parece más a una secuencia de cero o más sectores, determinada automáticamente. –

Respuesta

1

Citando las documentation:

Los siguientes tipos pueden ser encurtidos:

  • Ninguno, verdadero y falso
  • números enteros, números de punto flotante, números complejos
  • cuerdas, bytes , bytearrays
  • tuplas, listas, conjuntos y diccionarios que contienen solo objetos seleccionables
  • funciones definidas en el nivel superior de un módulo de
  • funciones incorporadas definen en el nivel superior de un módulo
  • clases que se definen en el nivel superior de un módulo de
  • casos de tales clases cuyos __dict__ o __ __setstate() es estibables (ver instancias sección de decapado Clase para más detalles)

los dos objetos en cuestión, Ellipsis y NotImplemented, no se ajustan a ninguna de estas reglas, y en consecuencia no puede ser pic kled.

Dudo que haya una razón mejor para no incluir todas las constantes integradas en la primera regla, salvo que nadie haya visto la necesidad de hacerlo. Si realmente crees que Pickle debería respaldar eso, considera publicar una solicitud de función (¡mejor traer un caso de uso convincente!).

+0

Vi esa lista, pero no estaba seguro de si era exclusiva. En particular, las funciones integradas como 'map' y' open' pueden escamotearse, pero no parecen ajustarse a ninguno de esos criterios (a menos que los considere 'definidos en el nivel superior de un módulo', en cuyo caso parece extraño que los gustos de 'NoneType' no se puedan escanear). – James

+2

'map' y' open' se definen en el nivel superior del módulo '__builtin__' (prueba' import __builtin__ como B; B.map'), 'NoneType' es una clase incorporada, no una función. ¡La documentación me parece consistente! –

+0

Hmm, eso tiene sentido, gracias por la explicación (¡aunque ahora me pregunto dónde está definido NoneType, si está en alguna parte!). Aunque realmente quería saber cuál es el razonamiento detrás de este comportamiento, tal vez debería enviar un informe de error. – James

4

No hay ninguna razón para que python no recoja elementos como Ellipsis y NotImplemented, y francamente al no tenerlos picklable contribuye a la fragilidad de python como un lenguaje paralelo/asincrónico. Puede agrupar este tipo de objetos con dill, un reemplazo para pickle.Sí, soy consciente de que esta es una diatriba leve, pero creo que NotImplemented en su código de destino no debería impedirle usar multiprocessing o algún otro de python paralelo ... o guardar el estado de su sesión de python para usarlo en otro momento … o lo que sea.

Python 3.2.5 (default, May 19 2013, 14:25:55) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import dill 
>>> dill.dumps(True) 
b'\x80\x03\x88.' 
>>> dill.dumps(False) 
b'\x80\x03\x89.' 
>>> dill.dumps(None) 
b'\x80\x03N.' 
>>> dill.dumps(Ellipsis) 
b'\x80\x03cdill.dill\n_eval_repr\nq\x00X\x08\x00\x00\x00Ellipsisq\x01\x85q\x02Rq\x03.' 
>>> dill.dumps(NotImplemented) 
b'\x80\x03cdill.dill\n_eval_repr\nq\x00X\x0e\x00\x00\x00NotImplementedq\x01\x85q\x02Rq\x03.' 

Obtener dill aquí: https://github.com/uqfoundation/dill

+0

Gracias por esto-- me hizo buscar y encontré este enlace que me ayudó a resolver mi problema paralelizando en IPython: http://nbviewer.ipython.org/gist/anonymous/5241793 – Omegaman

+0

@GB: impresionante. Ese es un buen enlace que publicaste. También soy consciente de que 'eneldo' se usa como reemplazo de salmuera en 'multiprocesamiento', 'mpi4py' y algunos otros paquetes de Python utilizados en computación paralela. –

Cuestiones relacionadas