Kann ich JSON dazu bringen, in ein OrderedDict zu laden?

Lesezeit: 6 Minuten

Benutzer-Avatar
c00kiemonster

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

Aber kann es als Ausgang verwendet werden? Wenn das so ist, wie? In meinem Fall würde ich gerne load in ein OrderedDict, damit ich die Reihenfolge der Schlüssel in der Datei beibehalten kann.

Wenn nicht, gibt es eine Art Workaround?

  • Ja, in meinem Fall überbrücke ich die Lücke zwischen verschiedenen Sprachen und Anwendungen, und JSON funktioniert sehr gut. Aber die Reihenfolge der Schlüssel ist ein bisschen ein Problem. Wäre toll, wenn es ein einfaches Häkchen geben würde json.load um OrderedDicts anstelle von Dicts in Python zu verwenden.

    – c00kiemonster

    3. August 2011 um 4:47 Uhr

  • Das ist ziemlich nervig. In Javascript (von dem json eine Teilmenge ist) wird die Reihenfolge der Schlüssel auch nicht beibehalten …

    – SingleNegationElimination

    3. August 2011 um 5:59 Uhr

  • Die JSON-Spezifikation definiert einen Objekttyp mit ungeordneten Schlüsseln … die Erwartung einer bestimmten Schlüsselreihenfolge ist ein Fehler

    – Anentrop

    10. Februar 2017 um 10:59 Uhr

  • Die Schlüsselreihenfolge ist normalerweise nicht für irgendeine Art von funktionalen Anforderungen. Es dient hauptsächlich nur der menschlichen Lesbarkeit. Wenn ich nur möchte, dass mein JSON hübsch gedruckt wird, erwarte ich nicht, dass sich irgendetwas an der Dokumentenreihenfolge ändert.

    – Essiggurken

    14. April 2017 um 22:56 Uhr

  • Es hilft auch, große Git-Diffs zu vermeiden!

    – Richard Rast

    12. Januar 2018 um 17:30 Uhr

Benutzer-Avatar
SingleNegationElimination

Ja, du kannst. Durch die Angabe der object_pairs_hook Argument zu JSONDecoder. Tatsächlich ist dies genau das Beispiel, das in der Dokumentation angegeben ist.

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

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

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

Verwenden json.load wird genauso gemacht:

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

  • Ich bin ratlos. Die Dokumentation sagt, dass der object_pairs_hook für jedes Literal aufgerufen wird, das in Paare dekodiert wird. Warum wird dadurch nicht für jeden Datensatz im JSON ein neues OrderedDict erstellt?

    – Tim Keating

    25. April 2014 um 19:33 Uhr

  • Hmm … die Dokumente sind etwas mehrdeutig formuliert. Was sie damit meinen, dass das “Gesamtergebnis der Dekodierung aller Paare” der Reihe nach als Liste übergeben wird object_pairs_hookanstatt “jedes Paar wird an object_pairs_hook übergeben”,

    – SingleNegationElimination

    25. April 2014 um 20:25 Uhr

  • Aber verliert die ursprüngliche Reihenfolge des Eingabe-json?

    – Islam

    5. Oktober 2016 um 15:02 Uhr

  • Behält das Hinzufügen des OrderedDict-Hooks die Befehle im Diktat in einer tieferen Hierarchie?

    – Zufällige Gewissheit

    6. August 2019 um 14:50 Uhr

  • @RandomCertainty ja, jedes Mal, wenn beim Analysieren der Quelle auf ein JSON-Objekt gestoßen wird, OrderedDict wird verwendet, um den resultierenden Python-Wert aufzubauen.

    – SingleNegationElimination

    22. August 2019 um 0:33 Uhr

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)

  • Ahhh, aber es enthält nicht den object_pairs_hook – weshalb Sie immer noch simplejson in 2.6 benötigen. 😉

    – mjhm

    3. August 2011 um 9:05 Uhr

  • Möchte das anmerken simplejson und ordereddict sind separate Bibliotheken, die Sie installieren müssen.

    – phunehehe

    14. Dezember 2011 um 7:18 Uhr

  • für Python 2.7+: „import json, collections“ im Code, für python2.6- „aptitude install python-pip“ und „pip install ordereddict“ im System

    – ZiTAL

    30. Januar 2012 um 15:33 Uhr

  • Dies ist viel einfacher und schneller als die vorherige Methode mit JSONDecoder.

    – Natim

    19. September 2012 um 13:23 Uhr

  • Seltsamerweise wird der enthaltene Json in Pypy dies nicht tun loads('{}', object_pairs_hook=OrderedDict).

    – Matthäus Schinckel

    19. April 2013 um 10:59 Uhr

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. Beachten 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 ab Python 3.7 zu einer Sprachspezifikation geworden ist (im Gegensatz zu einem Implementierungsdetail von cPython 3.6+): https://mail.python.org/pipermail/python-dev/2017-December/151283.html

Die Antwort auf Ihre Frage lautet also jetzt: Upgrade auf Python 3.6! 🙂

  • Obwohl ich im angegebenen Beispiel das gleiche Verhalten wie Sie sehe, in der CPython-Implementierung von Python 3.6.4, json.loads('{"2": 2, "1": 1}') wird {'1': 1, '2': 2} Für mich.

    – Flüchtling

    3. Juni 2018 um 18:55 Uhr

  • @fuglede so sieht es aus dict.__repr__ sortiert Schlüssel, während die zugrunde liegende Reihenfolge beibehalten wird. Mit anderen Worten, json.loads('{"2": 2, "1": 1}').items() ist dict_items([('2', 2), ('1', 1)]) selbst wenn repr(json.loads('{"2": 2, "1": 1}')) ist "{'1': 1, '2': 2}".

    – Simon Charette

    8. Februar 2019 um 23:00 Uhr

  • @SimonCharette Hm, könnte sein; Ich bin tatsächlich nicht in der Lage, meine eigene Beobachtung in Condas pkgs/main/win-64::python-3.6.4-h0c2934d_3 zu reproduzieren, daher wird dies schwer zu testen sein.

    – Flüchtling

    9. Februar 2019 um 8:48 Uhr


  • Dies hilft jedoch nicht wirklich weiter, da das “Umbenennen” von Schlüsseln immer noch die Reihenfolge der Schlüssel ruiniert.

    – Hubro

    30. Januar 2020 um 13:44 Uhr

  • Link zur Python-Dokumentation — In der Dokumentation wird erwähnt, dass “ab Python 3.7 das reguläre Diktat zur Beibehaltung der Reihenfolge wurde, sodass es nicht mehr erforderlich ist, es anzugeben collections.OrderedDict für die JSON-Generierung und -Analyse.”, was bedeutet, dass die Last standardmäßig in die eingefügt wird dict in der richtigen Reihenfolge.

    – Benutzer202729

    4. November 2020 um 13:58 Uhr

Sie könnten die Liste der Schlüssel immer zusätzlich zum Dumping des Diktats aufschreiben und dann rekonstruieren OrderedDict durch Iteration durch die Liste?

Benutzer-Avatar
Eric O Lebigot

Zusätzlich zum Ausgeben der geordneten Liste von Schlüsseln neben dem Wörterbuch besteht eine weitere Low-Tech-Lösung, die den Vorteil hat, explizit zu sein, darin, die (geordnete) Liste von Schlüssel-Wert-Paaren auszugeben ordered_dict.items(); Das Laden ist einfach 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 zu nutzen, dass json gibt das OrderedDict in der richtigen Reihenfolge aus. Es ist jedoch im Allgemeinen unnötig schwer und nicht unbedingt sinnvoll, es lesen zu müssen alle JSON-Wörterbücher als OrderedDict (über die object_pairs_hook Argument), also eine explizite Konvertierung von nur Sinnvoll sind auch die zu bestellenden Wörterbücher.

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

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

1110380cookie-checkKann ich JSON dazu bringen, in ein OrderedDict zu laden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy