¿Los elementos en el objeto JSON están fuera de orden usando “json.dumps”?

Estoy usando json.dumps para convertir en json como

 countries.append({"id":row.id,"name":row.name,"timezone":row.timezone}) print json.dumps(countries) 

El resultado que tengo es:

 [ {"timezone": 4, "id": 1, "name": "Mauritius"}, {"timezone": 2, "id": 2, "name": "France"}, {"timezone": 1, "id": 3, "name": "England"}, {"timezone": -4, "id": 4, "name": "USA"} ] 

Quiero tener las claves en el siguiente orden: id, nombre, zona horaria, pero en cambio tengo zona horaria, id, nombre.

¿Cómo debo arreglar esto?

Tanto Python dict (antes de Python 3.7) como el objeto JSON son colecciones no ordenadas. Podría pasar el parámetro sort_keys , para ordenar las claves:

 >>> import json >>> json.dumps({'a': 1, 'b': 2}) '{"b": 2, "a": 1}' >>> json.dumps({'a': 1, 'b': 2}, sort_keys=True) '{"a": 1, "b": 2}' 

Si necesita una orden particular; Podrías usar collections.OrderedDict :

 >>> from collections import OrderedDict >>> json.dumps(OrderedDict([("a", 1), ("b", 2)])) '{"a": 1, "b": 2}' >>> json.dumps(OrderedDict([("b", 2), ("a", 1)])) '{"b": 2, "a": 1}' 

Desde Python 3.6 , el orden de los argumentos de palabras clave se conserva y lo anterior se puede reescribir usando una syntax más agradable:

 >>> json.dumps(OrderedDict(a=1, b=2)) '{"a": 1, "b": 2}' >>> json.dumps(OrderedDict(b=2, a=1)) '{"b": 2, "a": 1}' 

Ver PEP 468 – Preservar el orden de argumentos de palabras clave .

Si su entrada se da como JSON, para conservar el orden (para obtener OrderedDict ), puede pasar object_pair_hook , como lo sugiere @Fred Yankowski :

 >>> json.loads('{"a": 1, "b": 2}', object_pairs_hook=OrderedDict) OrderedDict([('a', 1), ('b', 2)]) >>> json.loads('{"b": 2, "a": 1}', object_pairs_hook=OrderedDict) OrderedDict([('b', 2), ('a', 1)]) 

Como otros han mencionado, el dictamen subyacente no está ordenado. Sin embargo, hay objetos OrderedDict en Python. (Están incorporados en pythons recientes, o puede usar esto: http://code.activestate.com/recipes/576693/ ).

Creo que las nuevas implementaciones de pythons json manejan correctamente los OrderedDicts incorporados, pero no estoy seguro (y no tengo acceso fácil a la prueba).

Las implementaciones antiguas de pythons simplejson no manejan bien los objetos OrderedDict … y los convierten a dicts regulares antes de enviarlos … pero puede superar esto haciendo lo siguiente:

 class OrderedJsonEncoder( simplejson.JSONEncoder ): def encode(self,o): if isinstance(o,OrderedDict.OrderedDict): return "{" + ",".join( [ self.encode(k)+":"+self.encode(v) for (k,v) in o.iteritems() ] ) + "}" else: return simplejson.JSONEncoder.encode(self, o) 

Ahora usando esto obtenemos:

 >>> import OrderedDict >>> unordered={"id":123,"name":"a_name","timezone":"tz"} >>> ordered = OrderedDict.OrderedDict( [("id",123), ("name","a_name"), ("timezone","tz")] ) >>> e = OrderedJsonEncoder() >>> print e.encode( unordered ) {"timezone": "tz", "id": 123, "name": "a_name"} >>> print e.encode( ordered ) {"id":123,"name":"a_name","timezone":"tz"} 

Que es prácticamente lo que se desea.

Otra alternativa sería especializar el codificador para usar directamente su clase de fila, y luego no necesitaría ningún dict intermedio o UnorderedDict.

El orden de un diccionario no tiene ninguna relación con el orden en el que se definió. Esto se aplica a todos los diccionarios, no solo a los convertidos en JSON.

 >>> {"b": 1, "a": 2} {'a': 2, 'b': 1} 

De hecho, el diccionario se puso “al revés” antes de que incluso alcanzara json.dumps :

 >>> {"id":1,"name":"David","timezone":3} {'timezone': 3, 'id': 1, 'name': 'David'} 

En JSON, como en Javascript, el orden de las claves de objeto no tiene sentido, por lo que realmente no importa en qué orden se muestran, es el mismo objeto.

json.dump () conservará el orden de su diccionario. Abra el archivo en un editor de texto y verá. Conservará el orden independientemente de si le envía un OrderedDict.

Pero json.load () perderá el orden del objeto guardado a menos que le digas que cargue en OrderedDict (), que se realiza con el parámetro object_pairs_hook como JFSebastian se indicó anteriormente.

De lo contrario, perdería el orden porque, en la operación habitual, carga el objeto de diccionario guardado en un dictado regular y un dictado regular no conserva el orden de los elementos que se le dan.