wake-up-neo.com

Kann ich JSON in ein OrderedDict laden lassen?

Ok, damit ich ein OrderedDict in json.dump Verwenden kann. Das heißt, ein OrderedDict kann als Eingabe für JSON verwendet werden.

Aber kann es als Ausgabe verwendet werden? Wenn das so ist, wie? In meinem Fall möchte ich load in ein OrderedDict einfügen, damit ich die Reihenfolge der Schlüssel in der Datei beibehalten kann.

Wenn nicht, gibt es eine Art Workaround?

405
c00kiemonster

Ja, du kannst. Durch Angabe des Arguments object_pairs_hook Für JSONDecoder . In der Tat ist dies das genaue Beispiel in der Dokumentation.

>>> json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode('{"foo":1, "bar": 2}')
OrderedDict([('foo', 1), ('bar', 2)])
>>> 

Sie können diesen Parameter an json.loads Übergeben (falls Sie keine Decoder-Instanz für andere Zwecke benötigen):

>>> import json
>>> from collections import OrderedDict
>>> data = json.loads('{"foo":1, "bar": 2}', object_pairs_hook=OrderedDict)
>>> print json.dumps(data, indent=4)
{
    "foo": 1,
    "bar": 2
}
>>> 

Die Verwendung von json.load Geschieht auf die gleiche Weise:

>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)

Einfache Version für Python 2.7+

my_ordered_dict = json.loads(json_str, object_pairs_hook=collections.OrderedDict)

Oder für Python 2.4 bis 2.6

import simplejson as json
import ordereddict

my_ordered_dict = json.loads(json_str, object_pairs_hook=ordereddict.OrderedDict)
124
mjhm

Tolle Neuigkeiten! Seit Version 3.6 hat die cPython-Implementierung die Einfügereihenfolge von Wörterbüchern beibehalten ( https://mail.python.org/pipermail/python-dev/2016-September/146327.html ). Dies bedeutet, dass die json-Bibliothek jetzt standardmäßig die Reihenfolge beibehält. Beobachten Sie den Unterschied im Verhalten zwischen python 3.5 und 3.6. Der Code:

import json
data = json.loads('{"foo":1, "bar":2, "fiddle":{"bar":2, "foo":1}}')
print(json.dumps(data, indent=4))

In py3.5 ist die resultierende Reihenfolge undefiniert:

{
    "fiddle": {
        "bar": 2,
        "foo": 1
    },
    "bar": 2,
    "foo": 1
}

In der cPython-Implementierung von python 3.6:

{
    "foo": 1,
    "bar": 2,
    "fiddle": {
        "bar": 2,
        "foo": 1
    }
}

Die wirklich gute Nachricht ist, dass dies eine Sprachspezifikation ab python 3.7 (im Gegensatz zu einem Implementierungsdetail von cPython 3.6+) geworden ist): https: //mail.python. org/pipermail/python-dev/2017-December/151283.html

Die Antwort auf Ihre Frage lautet nun: Upgrade auf python 3.6! :)

29
pelson

Sie könnten die Liste der Schlüssel zusätzlich zum Dump des Diktats immer ausschreiben und dann das OrderedDict rekonstruieren, indem Sie die Liste durchlaufen?

7
Amber

Zusätzlich zum Speichern der geordneten Liste der Schlüssel neben dem Wörterbuch besteht eine andere Low-Tech-Lösung, die den Vorteil hat, explizit zu sein, darin, die (geordnete) Liste der Schlüssel-Wert-Paare ordered_dict.items() zu speichern. Laden ist ein einfaches OrderedDict(<list of key-value pairs>). Dies behandelt ein geordnetes Wörterbuch, obwohl JSON dieses Konzept nicht hat (JSON-Wörterbücher haben keine Reihenfolge).

Es ist in der Tat schön, die Tatsache auszunutzen, dass json das OrderedDict in der richtigen Reihenfolge ausgibt. Es ist jedoch im Allgemeinen unnötig schwer und nicht unbedingt sinnvoll, alle JSON-Wörterbücher als OrderedDict lesen zu müssen (über object_pairs_hook Argument), daher ist auch eine explizite Konvertierung von nur der Wörterbücher, die bestellt werden müssen, sinnvoll.

5
Eric O Lebigot

Der normalerweise verwendete Ladebefehl funktioniert, wenn Sie den Parameter object_pairs_hook angeben:

import json
from  collections import OrderedDict
with open('foo.json', 'r') as fp:
    metrics_types = json.load(fp, object_pairs_hook=OrderedDict)
3
ntg