¿Los elementos del objeto JSON están desordenados usando "json.dumps"?

Resuelto Noor asked hace 12 años • 8 respuestas

Estoy usando json.dumpspara convertir a 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 su lugar tengo zona horaria, id, nombre.

¿Cómo debería solucionar esto?

Noor avatar Jun 01 '12 10:06 Noor
Aceptado

Tanto Python dict(antes de Python 3.7) como el objeto JSON son colecciones desordenadas. Puede pasar sort_keysel parámetro 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 un pedido en particular; podrías usarcollections.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 las palabras clave se conserva y lo anterior se puede reescribir usando una sintaxis 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}'

Consulte PEP 468: Preservación del orden de los argumentos de las palabras clave .

Si su entrada se proporciona como JSON, para preservar 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)])
jfs avatar May 23 '2014 03:05 jfs

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

Creo que las implementaciones json de Python más nuevas manejan correctamente los OrderedDicts integrados, pero no estoy seguro (y no tengo fácil acceso a las pruebas).

Las implementaciones antiguas de Python simplejson no manejan bien los objetos OrderedDict... y los convierten en dictados normales antes de generarlos... pero puedes 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"}

Lo cual es más o menos lo deseado.

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

Michael Anderson avatar Jun 01 '2012 04:06 Michael Anderson

Oye, sé que es muy tarde para esta respuesta, pero agrega sort_keys y asígnale false de la siguiente manera:

json.dumps({'****': ***},sort_keys=False)

esto funcionó para mí

Rabiea Ez Eldeen avatar Jul 19 '2019 18:07 Rabiea Ez Eldeen

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 a JSON.

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

De hecho, el diccionario se puso "patas arriba" antes de llegar a json.dumps:

>>> {"id":1,"name":"David","timezone":3}
{'timezone': 3, 'id': 1, 'name': 'David'}
David Robinson avatar Jun 01 '2012 03:06 David Robinson