¿Los elementos del objeto JSON están desordenados usando "json.dumps"?
Estoy usando json.dumps
para 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?
Tanto Python dict
(antes de Python 3.7) como el objeto JSON son colecciones desordenadas. Puede pasar sort_keys
el 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)])
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.
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í
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'}