ordereddict dict python dictionary cpython ordereddictionary dictionary-comprehension

python - ordereddict to json



OrderedDict comprehensions (3)

Lo siento no es posible. Dict literales y dict comprehensions se asignan al tipo de dict incorporado, de una manera que está codificada en el nivel C. Eso no puede ser anulado.

Puede usar esto como una alternativa, sin embargo:

OrderedDict((i, i * i) for i in range(3))

Adición: a partir de Python 3.6, todos los diccionarios de Python están ordenados. A partir del 3.7, es incluso parte de la especificación del idioma. Si está usando esas versiones de Python, no necesita OrderedDict: la comprensión dict será Just Work (TM).

¿Puedo extender la sintaxis en python para las comprensiones dict para otros dicts, como el OrderedDict en el módulo de collections o mis propios tipos que heredan de dict ?

Simplemente volver a enlazar el nombre del dict obviamente no funciona, la sintaxis de comprensión de {key: value} aún te da un viejo dict simple para las comprensiones y los literales.

>>> from collections import OrderedDict >>> olddict, dict = dict, OrderedDict >>> {i: i*i for i in range(3)}.__class__ <type ''dict''>

Entonces, si es posible, ¿cómo voy a hacer eso? Está bien si solo funciona en CPython. En cuanto a la sintaxis, supongo que la probaría con un prefijo O{k: v} como el que tenemos en la r''various'' u''string'' b''objects'' .

Nota: Por supuesto, podemos usar una expresión de generador en su lugar, pero estoy más interesado en ver cuán pirateable es Python en términos de la gramática.


Modificando levemente la respuesta de @Max Noel, puedes usar la comprensión de listas en lugar de un generador para crear un OrderedDict de una manera ordenada (lo que por supuesto no es posible usando la comprensión dict).

>>> OrderedDict([(i, i * i) for i in range(5)]) OrderedDict([(0, 0), (1, 1), (2, 4), (3, 9), (4, 16)])


No hay una forma directa de cambiar la sintaxis de Python desde dentro del lenguaje. La comprensión de un diccionario (o visualización simple) siempre creará un dict , y no hay nada que puedas hacer al respecto. Si está usando CPython, está utilizando PyDict especiales que generan un dict directamente, que finalmente llama a las funciones de PyDict API y / o las mismas funciones subyacentes utilizadas por esa API. Si está utilizando PyPy, esos códigos de bytes se implementan sobre un objeto dict RPython que a su vez se implementa sobre un dict Python compilado y optimizado. Y así.

Hay una forma indirecta de hacerlo, pero no te va a gustar. Si lee los documentos en el sistema de importación , verá que es el importador que busca el código compilado en caché o llama al compilador y al compilador que llama al analizador, y así sucesivamente. En Python 3.3+, casi todo en esta cadena está escrito en Python puro, o tiene una implementación de Python pura alternativa, lo que significa que puede bifurcar el código y hacer lo suyo. Que incluye analizar fuente con su propio código PyParsing que construye ASTs, o compilar un nodo AST de comprensión dict en su propio bytecode personalizado en lugar del predeterminado, o postprocesar el bytecode, o ...

En muchos casos, un gancho de importación es suficiente; si no, siempre puedes escribir un buscador y un cargador personalizados.

Si aún no está utilizando Python 3.3 o posterior, le recomiendo migrar antes de jugar con este material. En las versiones anteriores, es más difícil y está menos documentado, y en última instancia, tendrá que esforzarse 10 veces para aprender algo que se volverá obsoleto cada vez que migre.

De todos modos, si este enfoque te parece interesante, tal vez quieras echarle un vistazo a MacroPy . Podría tomar prestado algún código del mismo y, quizás lo más importante, aprender cómo se usan algunas de estas características (que no tienen buenos ejemplos en los documentos).

O bien, si está dispuesto a conformarse con algo menos interesante, puede usar MacroPy para crear una "macro de comprensión odiosa" y usar eso. (Tenga en cuenta que MacroPy actualmente solo funciona en Python 2.7, no 3.x.) No puede obtener o{…} , pero puede obtener, por ejemplo, od[{…}] , lo cual no es tan malo. Descargue od.py , realmain.py y main.py y ejecute python main.py para ver cómo funciona. La clave es este código, que toma un DictionaryComp AST, lo convierte en un GeneratorExpr equivalente en clave-valor Tuple s, y lo envuelve en una Call a collections.OrderedDict :

def od(tree, **kw): pair = ast.Tuple(elts=[tree.key, tree.value]) gx = ast.GeneratorExp(elt=pair, generators=tree.generators) odict = ast.Attribute(value=ast.Name(id=''collections''), attr=''OrderedDict'') call = ast.Call(func=odict, args=[gx], keywords=[]) return call

Una alternativa diferente es, por supuesto, modificar el intérprete de Python.

Sugeriría descartar la idea de sintaxis O{…} para su primer intento, y simplemente hacer que las compilaciones dict normales compilar a los odictos. La buena noticia es que realmente no necesitas cambiar la gramática (que está más allá de lo peludo ...), cualquiera de:

  • los bytecodes compilados por dictcomps,
  • la forma en que el intérprete ejecuta esos bytecodes, o
  • la implementación del tipo PyDict

Las malas noticias, aunque todas son mucho más fáciles que cambiar la gramática, ninguna de ellas se puede hacer desde un módulo de extensión. (Bueno, puedes hacer el primero haciendo básicamente lo mismo que harías con Python puro ... y puedes hacer cualquiera de ellos conectando el .so / .dll / .dylib al parche en tus propias funciones, pero eso es el mismo trabajo exacto que hackear en Python más el trabajo adicional de enganchar en tiempo de ejecución).

Si quiere piratear el origen de CPython , el código que desea está en Python/compile.c , Python/ceval.c , y Objects/dictobject.c , y la guía de desarrollo le dice cómo encontrar todo lo que necesita. Pero es posible que desee considerar piratear PyPy source en su lugar, ya que está escrito principalmente en (un subconjunto de) Python en lugar de C.

Como nota al margen, su intento no habría funcionado, incluso si todo se hizo en el nivel de idioma de Python. olddict, dict = dict, OrderedDict crea un enlace denominado dict en los globales de tu módulo, que sombrea el nombre en los builtins, pero no lo reemplaza. Puede reemplazar las cosas en los builtins (bueno, Python no garantiza esto, pero hay cosas específicas de la implementación / versión-que-pasar-a-trabajar para cada implementación / versión que he intentado ...), pero lo que hizo no es la forma de hacerlo.