¿Anular la notación {…} para obtener un OrderedDict () en lugar de un dict ()?

Quiero usar un archivo .py como un archivo de configuración. Entonces, usando la notación {...} puedo crear un diccionario usando cadenas como claves pero el orden de definición se pierde en un diccionario estándar de Python.

Mi pregunta: ¿es posible anular la notación {...} para obtener un OrderedDict() lugar de un dict() ?

Esperaba que simplemente anular dict constructor con OrderedDict ( dict = OrderedDict ) funcionara, pero no funciona.

P.ej:

 dict = OrderedDict dictname = { 'B key': 'value1', 'A key': 'value2', 'C key': 'value3' } print dictname.items() 

Salida:

     [('B key', 'value1'), ('A key', 'value2'), ('C key', 'value3')] 

    Aquí hay un hack que casi te da la syntax que deseas:

     class _OrderedDictMaker(object): def __getitem__(self, keys): if not isinstance(keys, tuple): keys = (keys,) assert all(isinstance(key, slice) for key in keys) return OrderedDict([(k.start, k.stop) for k in keys]) ordereddict = _OrderedDictMaker() 
     from nastyhacks import ordereddict menu = ordereddict[ "about" : "about", "login" : "login", 'signup': "signup" ] 

    Edición: alguien más descubrió esto de manera independiente y ha publicado el paquete odictliteral en PyPI que proporciona una implementación un poco más completa. odictliteral esto en su lugar

    Para obtener literalmente lo que está pidiendo, debe jugar con el árbol de syntax de su archivo. No creo que sea recomendable hacerlo, pero no pude resistir la tentación de intentarlo. Así que, aquí vamos.

    Primero, creamos un módulo con una función my_execfile() que funciona como el execfile() , excepto que todas las apariciones de diccionario se muestran, por ejemplo, {3: 4, "a": 2} se reemplazan por llamadas explícitas al constructor dict() , por ejemplo, dict([(3, 4), ('a', 2)]) . (Por supuesto, podríamos reemplazarlos directamente con llamadas a collections.OrderedDict() , pero no queremos ser demasiado intrusivos). Aquí está el código:

     import ast class DictDisplayTransformer(ast.NodeTransformer): def visit_Dict(self, node): self.generic_visit(node) list_node = ast.List( [ast.copy_location(ast.Tuple(list(x), ast.Load()), x[0]) for x in zip(node.keys, node.values)], ast.Load()) name_node = ast.Name("dict", ast.Load()) new_node = ast.Call(ast.copy_location(name_node, node), [ast.copy_location(list_node, node)], [], None, None) return ast.copy_location(new_node, node) def my_execfile(filename, globals=None, locals=None): if globals is None: globals = {} if locals is None: locals = globals node = ast.parse(open(filename).read()) transformed = DictDisplayTransformer().visit(node) exec compile(transformed, filename, "exec") in globals, locals 

    Con esta modificación en su lugar, podemos modificar el comportamiento de las visualizaciones de diccionarios al sobrescribir el dict . Aquí hay un ejemplo:

     # test.py from collections import OrderedDict print {3: 4, "a": 2} dict = OrderedDict print {3: 4, "a": 2} 

    Ahora podemos ejecutar este archivo usando my_execfile("test.py") , produciendo el resultado

     {'a': 2, 3: 4} OrderedDict([(3, 4), ('a', 2)]) 

    Tenga en cuenta que, para simplificar, el código anterior no toca la comprensión del diccionario, que debe transformarse en expresiones generadoras pasadas al constructor dict() . Necesitaría agregar un método visit_DictComp() a la clase DictDisplayTransformer . Dado el código de ejemplo anterior, esto debería ser sencillo.

    De nuevo, no recomiendo este tipo de problemas con la semántica del lenguaje. ¿Has ConfigParser un vistazo al módulo ConfigParser ?

    OrderedDict no es una “syntax estándar de python”, sin embargo, un conjunto ordenado de pares clave-valor (en la syntax estándar de python) es simplemente:

     [('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')] 

    Para obtener explícitamente un OrderedDict :

     OrderedDict([('key1 name', 'value1'), ('key2 name', 'value2'), ('key3 name', 'value3')]) 

    Otra alternativa, es ordenar dictname.items() , si eso es todo lo que necesita:

     sorted(dictname.items()) 

    Lo que está pidiendo es imposible, pero si un archivo de configuración en syntax JSON es suficiente, puede hacer algo similar con el módulo json :

     >>> import json, collections >>> d = json.JSONDecoder(object_pairs_hook = collections.OrderedDict) >>> d.decode('{"a":5,"b":6}') OrderedDict([(u'a', 5), (u'b', 6)]) 

    La única solución que encontré es parchear el propio python, haciendo que el objeto dict recuerde el orden de inserción.

    Esto funciona para todo tipo de syntax:

     x = {'a': 1, 'b':2, 'c':3 } y = dict(a=1, b=2, c=3) 

    etc.

    He tomado la implementación de ordereddict C de https://pypi.python.org/pypi/ruamel.ordereddict/ y me he fusionado de nuevo con el código principal de python.

    Si no le importa reconstruir el intérprete de Python, aquí hay un parche para Python 2.7.8: https://github.com/fwyzard/cpython/compare/2.7.8…ordereddict-2.7.8.diff . UNA

    A partir de Python 3.6, todos los diccionarios se ordenarán de forma predeterminada . Por ahora, este es un detalle de implementación de dict y no se debe confiar en él, pero es probable que se convierta en estándar después de v3.6.

    El orden de inserción siempre se conserva en la nueva implementación de dict :

     >>>x = {'a': 1, 'b':2, 'c':3 } >>>list(x.keys()) ['a', 'b', 'c'] 

    A partir de Python 3.6 **kwargs orden de **kwargs [PEP468] y el orden de atributo de clase [ PEP520 ]. La nueva implementación compacta y ordenada del diccionario se utiliza para implementar el pedido de ambos.

    Si lo que busca es una forma de obtener una syntax de inicialización fácil de usar, considere crear una subclase de OrderedDict y agregarle operadores que actualicen el dictado, por ejemplo:

     from collections import OrderedDict class OrderedMap(OrderedDict): def __add__(self,other): self.update(other) return self d = OrderedMap()+{1:2}+{4:3}+{"key":"value"} 

    d será – OrderedMap ([(1, 2), (4, 3), (‘key’, ‘value’)])


    Otro posible ejemplo de azúcar sintáctica utilizando la syntax de corte:

     class OrderedMap(OrderedDict): def __getitem__(self, index): if isinstance(index, slice): self[index.start] = index.stop return self else: return OrderedDict.__getitem__(self, index) d = OrderedMap()[1:2][6:4][4:7]["a":"H"]