2015-08-20 6 views
5

Ich analysiere den JSON von der Web-API, und Python scheint die Schlüssel zu mischen, wenn ich über sie iteriere.JSON-Schlüssel werden in Python gemischt

Original-JSON auf Screenshot (. Es richtig ursprüngliche Reihenfolge ist Nein, es ist nicht nur alphabetisch sortiert): Original JSON

Mein Code:

data = requests.get('http://www.dota2.com/jsfeed/heropediadata?feeds=abilitydata&l=english').json() 

for key in data['abilitydata']: 
    print key 

und Ausgang:

tiny_avalanche 
rubick_fade_bolt 
doom_bringer_devour 
undying_flesh_golem 
... 

I habe auch versucht, dies über urllib & json.loads() - es gibt das gleiche Ergebnis.

Wie kann ich die ursprüngliche Bestellung erreichen?

+0

Können Sie es durch das Objekt zu lesen, und wie Sie jedes Lese Objekt einen Auftrag Schlüssel hinzufügen. Ich habe noch nie mit JSON gearbeitet, aber ich würde mir etwas vorstellen wie das erste Lesen der Datei und dann das Iterieren jedes Objekts und beim Konvertieren in JSON ein neues Attribut hinzufügen - die ursprüngliche Reihenfolge – PyNEwbie

+1

Ein JSON-Objekt ist [per Definition] (http://www.json.org), "eine ungeordnete Menge von Name/Wert-Paaren". Sie sollten wirklich keine JSON-Objekte verwenden (oder vielleicht sollten Sie nicht einmal JSON verwenden), wenn die Reihenfolge wichtig ist, in der die Schlüssel/Wert-Paare ursprünglich angegeben wurden. –

Antwort

5

Sie können ein geordnetes Wörterbuch und das Argument object_pairs_hook der Methode loads im json-Paket verwenden.Hier ist ein funktionierendes Codebeispiel:

import json 
import requests 
from collections import OrderedDict 

result = requests.get('http://www.dota2.com/jsfeed/heropediadata?feeds=abilitydata&l=english') 
data = json.loads(result.text, object_pairs_hook = OrderedDict) 

Daten enthält Ihre Wörterbuchschlüssel, um

+0

Danke, das hat bei mir funktioniert und das ist die kürzeste Lösung :) – arts777

1

Weil Python-Wörterbücher nicht geordnet sind.

Wenn Sie den JSON-Text analysieren, erhalten Sie ein Wörterbuch. Da der Dictionary-Typ keine Reihenfolge hat, können die Schlüssel nur in einer undefinierten Reihenfolge durchlaufen werden.

+0

Danke für die Erklärung. Gibt es eine Möglichkeit, mit der ursprünglichen Reihenfolge darüber zu iterieren? – arts777

+6

Selbst wenn Sie einen auftragserhaltenden Python-Typ verwenden (dh. Orderedict, der durch und durch verwendet werden müsste), ist es immer noch falsch, sich auf dieses Verhalten in JSON zu verlassen; JSON selbst legt explizit * nein * Reihenfolge der Schlüssel/Wert-Werte fest. – user2864740

+0

@ user2864740 das ist nur Dienstprogramm Parser, nicht produktionsbezogenen Code :) – arts777

1

dict Typ ist ein integrierter Typ in Python. Es ist ungeordnet. Wenn Sie die Reihenfolge der Schlüssel im Dict wiederherstellen möchten, können Sie OrderedDict aus der Klasse collections verwenden.

Sehen Sie folgendes Beispiel:

>>> import collections 
>>> data = collections.OrderedDict() 
>>> data['pear'] = 1 
>>> data['apple'] = 3 
>>> data['orange'] = 2 
>>> data['lemon'] = 4 
>>> 
>>> 
>>> print data 
OrderedDict([('pear', 1), ('apple', 3), ('orange', 2), ('lemon', 4)]) 
>>> 
>>> 
>>> data2 = dict() 
>>> data2['pear'] = 1 
>>> data2['apple'] = 3 
>>> data2['orange'] = 2 
>>> data2['lemon'] = 4 
>>> 
>>> 
>>> print data2 
{'orange': 2, 'lemon': 4, 'pear': 1, 'apple': 3} 
>>> 

Für weitere Informationen, gehen Sie durch diese: https://docs.python.org/2/library/collections.html#collections.OrderedDict

3

Wie die anderen gesagt haben, dict ungeordnet ist. collections.OrderedDict ist eine dict-Unterklasse, deren Schlüssel geordnet sind. Das Problem ist, dass json.load eine dict direkt zurückgibt, und wir können nicht einfach das Ergebnis in eine werfen, da die Reihenfolge der Schlüssel bereits Informationen zu diesem Zeitpunkt verloren ist.

Wir müssen einen Weg json.load zu sagen, ein OrderedDict anstelle eines dict .Dieses zurückkehren kann durch die Implementierung eines benutzerdefinierten json.JSONDecoder, die ein object_pairs_hook liefert erfolgen. Die object_pairs_hook erhält ein JSON-Objekt als eine Liste von (key, value) Tupel in der Reihenfolge, in der sie im JSON-Dokument erscheinen. Es sollte die Übersetzung dieses Objekts in ein Python-Objekt zurückgeben. Wir werden diese Tupelliste an den Initialisierer für collections.OrderedDict übergeben, und das sollte reichen.

Hier einige Code:

data = """ 
{ 
    "foo": "bar", 
    "a_list": [1, 2, 3], 
    "another_object": { 
     "c": 3, 
     "a": 1, 
     "b": 2 
     }, 
    "last_key": 42 
} 
""" 

decoder = json.JSONDecoder(object_pairs_hook=collections.OrderedDict) 
result = decoder.decode(data) 
print(result) 

die gibt:

OrderedDict([('foo', 'bar'), 
      ('a_list', [1, 2, 3]), 
      ('another_object', OrderedDict([('c', 3), ('a', 1), ('b', 2)])), 
      ('last_key', 42)]) 

Schließlich Sie fragen sich vielleicht, "Warum ist dies so viel zusätzliche Arbeit?". Nun, JSON soll nicht als Datenstruktur mit einer festen Reihenfolge behandelt werden. Sie gehen gegen den Strich, indem Sie dies tun.

+0

Danke! Tolle Erklärung. – arts777

Verwandte Themen