Gli articoli nell'oggetto JSON sono fuori servizio usando "json.dumps"?


157

Sto usando json.dumpsper convertire in json come

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

Il risultato che ho è:

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

Voglio avere le chiavi nel seguente ordine: id, nome, fuso orario - ma invece ho fuso orario, id, nome.

Come devo risolvere questo?

Risposte:


244

Sia Python dict(prima di Python 3.7) sia l'oggetto JSON sono raccolte non ordinate. È possibile passare il sort_keysparametro, per ordinare le chiavi:

>>> 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}'

Se hai bisogno di un ordine particolare; potresti usarecollections.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}'

A partire da Python 3.6 , l'ordine degli argomenti delle parole chiave viene preservato e quanto sopra può essere riscritto usando una sintassi migliore:

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

Vedere PEP 468 - Conservazione dell'ordine degli argomenti delle parole chiave .

Se il tuo input viene dato come JSON per preservare l'ordine (per ottenere OrderedDict), potresti passare object_pair_hook, come suggerito da @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)])

2
OrderedDict's init davvero brutto
jean

3
@jean: il valore iniziale non ha nulla a che fare con OrderedDict(), puoi passare un dicta OrderedDict(), puoi anche passare un elenco di coppie ordinate, dict()anche se l'ordine si perde in entrambi questi casi.
jfs,

Intendo iniziarlo quando preservare l'ordine, è necessario digitare molti '(' e ')'
jean,


25
Inoltre, se si carica JSON utilizzando d = json.load(f, object_pairs_hook=OrderedDict), una versione successiva json.dump(d)manterrà l'ordine degli elementi originali.
Fred Yankowski

21

Come altri hanno già detto, il dict sottostante non è ordinato. Tuttavia ci sono oggetti OrderedDict in Python. (Sono integrati negli ultimi pitoni, oppure puoi usare questo: http://code.activestate.com/recipes/576693/ ).

Credo che le più recenti implementazioni di Pythons JSON gestiscano correttamente i OrderedDicts integrati, ma non ne sono sicuro (e non ho un facile accesso al test).

Le vecchie implementazioni di Pythons simplejson non gestiscono bene gli oggetti OrderedDict .. e non li convertono in dadi regolari prima di emetterli .. ma puoi superarlo nel modo seguente:

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)

ora usando questo otteniamo:

>>> 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"}

Che è praticamente come desiderato.

Un'altra alternativa sarebbe quella di specializzare il codificatore per utilizzare direttamente la classe di riga e quindi non avresti bisogno di alcun dict intermedio o UnorderedDict.


5
Si noti che gli oggetti JSON sono ancora non ordinati ; un client JSON può leggere la definizione dell'oggetto e ignorare completamente l'ordine delle chiavi ed essere pienamente conforme a RFC.
Martijn Pieters

4
Martijn ha ragione, ciò non influisce sulla conformità RFC, ma può sicuramente essere utile se si desidera avere un formato coerente per il proprio JSON (ad esempio se il file è sotto il controllo della versione o per rendere più semplice per un lettore umano comprendere, di fare in modo che l'ordine di entrata corrisponda alla documentazione.)
Michael Anderson

3
Nel qual caso hai appena impostato sort_keyssu Truequando si chiama json.dumps(); per la stabilità degli ordini (per test, memorizzazione nella cache stabile o commit VCS), è sufficiente ordinare le chiavi.
Martijn Pieters

7

L'ordine di un dizionario non ha alcuna relazione con l'ordine in cui è stato definito. Questo vale per tutti i dizionari, non solo per quelli trasformati in JSON.

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

In effetti, il dizionario è stato capovolto prima ancora che raggiungesse json.dumps:

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

6

hey so che è così tardi per questa risposta, ma aggiungi sort_keys e assegna falso come segue:

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

questo ha funzionato per me


4

json.dump () conserverà l'ordinatore del dizionario. Apri il file in un editor di testo e vedrai. Conserverà l'ordine indipendentemente dal fatto che lo invii un OrderedDict.

Ma json.load () perderà l'ordine dell'oggetto salvato a meno che tu non gli dica di caricarlo in un OrderedDict (), che viene fatto con il parametro object_pairs_hook come JFSebastian ha indicato sopra.

Altrimenti perderebbe l'ordine perché, durante le normali operazioni, carica l'oggetto dizionario salvato in un dict regolare e un dict regolare non conserva il resto degli elementi che gli vengono dati.


Questa è in realtà una soluzione migliore in quanto il mantenimento dell'ordine al carico si occupa dell'ordinamento dei tempi di scarico. Grazie per questa risposta
Arun R,

2

in JSON, come in Javascript, l'ordine delle chiavi dell'oggetto non ha senso, quindi non importa in quale ordine vengano visualizzate, è lo stesso oggetto.


(e lo stesso vale anche per un Python standard dict)

12
ma poiché JSON è una rappresentazione di stringa fino a quando non viene analizzata, i confronti di stringhe (come nei doctest) potrebbero richiedere ancora un ordine. Quindi non direi che non importa mai.
Michael Scott Cuthbert,

1
Sebbene ciò sia vero per lo standard Javascript (script ECMA), tutte le implementazioni mantengono le chiavi (stringa) nell'ordine dei sorgenti.
thebjorn,

1
@Paulpro davvero? quale? So che Chrome ha provato a seguire lo standard qui una volta, ma è stato inserito nell'invio ( code.google.com/p/v8/issues/detail?id=164 ). Non pensavo che qualcuno avrebbe provato la stessa cosa dopo quello ...
thebjorn

2
@paulpro stai rispondendo correttamente alla domanda del PO. Voglio aggiungere, tuttavia, che esistono usi legittimi per preservare l'ordine. Ad esempio, si può scrivere uno script che legge JSON, applica alcune trasformazioni e riscrive i risultati. Vorresti preservare l'ordine in modo che uno strumento diff mostrasse chiaramente le modifiche.
Paul Rademacher,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.