Ich möchte Python verwenden, um JSON-Daten in ein Python-Objekt zu konvertieren.
Ich erhalte JSON-Datenobjekte von der Facebook-API, die ich in meiner Datenbank speichern möchte.
Meine aktuelle Ansicht in Django (Python) ( request.POST
enthält den JSON):
response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
Das funktioniert gut, aber wie gehe ich mit komplexen JSON-Datenobjekten um?
Wäre es nicht viel besser, wenn ich dieses JSON-Objekt zur einfachen Verwendung in ein Python-Objekt konvertieren könnte?
dict
s ist eine Methode mit schwacher Sauce, um objektorientiert zu programmieren. Wörterbücher sind eine sehr schlechte Möglichkeit, den Lesern Ihres Codes Erwartungen zu vermitteln. Wie können Sie mithilfe eines Wörterbuchs klar und wiederverwendbar angeben, dass einige Wörterbuchschlüssel-Wert-Paare erforderlich sind, andere nicht? Wie wäre es mit der Bestätigung, dass ein bestimmter Wert im akzeptablen Bereich oder Satz liegt? Was ist mit Funktionen, die spezifisch für den Objekttyp sind, mit dem Sie arbeiten (auch bekannt als Methoden)? Wörterbücher sind praktisch und vielseitig, aber zu viele Entwickler tun so, als hätten sie vergessen, dass Python aus einem bestimmten Grund eine objektorientierte Sprache ist.Antworten:
Sie können dies in einer Zeile mit
namedtuple
und tunobject_hook
:oder, um dies einfach wiederzuverwenden:
Wenn Sie möchten, dass Schlüssel verarbeitet werden, die keine guten Attributnamen sind, überprüfen Sie
namedtuple
denrename
Parameter .quelle
d.keys()
und sie zud.values()
wiederholen, aber ich habe mich geirrt. In den Dokumenten heißt es: "Wenn Schlüssel-, Werte- und Elementansichten ohne dazwischenliegende Änderungen am Wörterbuch wiederholt werden, entspricht die Reihenfolge der Elemente direkt." Gut zu wissen für so kleine, lokale Codeblöcke. Ich würde jedoch einen Kommentar hinzufügen, um die Betreuer des Codes explizit auf eine solche Abhängigkeit aufmerksam zu machen.x._asdict()
, was in einfachen Fällen hilfreich sein kann .Lesen Sie den Abschnitt mit dem Titel Spezialisieren der JSON-Objektdecodierung in der
json
Moduldokumentation . Damit können Sie ein JSON-Objekt in einen bestimmten Python-Typ dekodieren.Hier ist ein Beispiel:
Aktualisieren
Wenn Sie über das json-Modul auf Daten in einem Wörterbuch zugreifen möchten, gehen Sie folgendermaßen vor:
Genau wie ein normales Wörterbuch.
quelle
Dies ist kein Code-Golf, aber hier ist mein kürzester Trick, der
types.SimpleNamespace
als Container für JSON-Objekte verwendet wird.Im Vergleich zur führenden
namedtuple
Lösung ist es:rename
Option und wahrscheinlich die gleiche Einschränkung für Schlüssel, die keine gültigen Bezeichner sind (Verwendungsetattr
unter dem Deckmantel).Beispiel:
quelle
@post_load
Dekorator eine ähnliche Funktion . marshmallow.readthedocs.io/en/latest/…from types import SimpleNamespace
und verwenden Sie:x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
types.SimpleNamespace
existiert in 2.7 leider nicht).print_function
?Sie könnten dies versuchen:
Erstellen Sie einfach ein neues Objekt und übergeben Sie die Parameter als Karte.
quelle
Hier ist eine schnelle und schmutzige Alternative zu json pickle
quelle
Für komplexe Objekte können Sie JSON Pickle verwenden
quelle
jsonstruct originally a fork of jsonpickle (Thanks guys!). The key difference between this library and jsonpickle is that during deserialization, jsonpickle requires Python types to be recorded as part of the JSON. This library intends to remove this requirement, instead, requires a class to be passed in as an argument so that its definition can be inspected. It will then return an instance of the given class. This approach is similar to how Jackson (of Java) works.
'[{"name":"object1"},{"name":"object2"}]'
. jsonpickle geht auch nicht sehr gut damit um.Wenn Sie Python 3.5+ verwenden, können Sie damit
jsons
alte Python-Objekte serialisieren und deserialisieren:Sie könnten auch für mehr Eleganz
FbApiUser
erbenjsons.JsonSerializable
:Diese Beispiele funktionieren, wenn Ihre Klasse aus Python-Standardtypen wie Zeichenfolgen, Ganzzahlen, Listen, Datumsangaben usw. besteht. Die Bibliothek
jsons
erfordert jedoch Typhinweise für benutzerdefinierte Typen.quelle
Wenn Sie Python 3.6+ verwenden, können Sie die Marshmallow-Datenklasse verwenden . Im Gegensatz zu allen oben aufgeführten Lösungen ist es sowohl einfach als auch typsicher:
quelle
TypeError: make_data_class() got an unexpected keyword argument 'many'
Ich habe ein kleines ( De- ) Serialisierungsframework namens any2any geschrieben , das bei komplexen Transformationen zwischen zwei Python-Typen hilft.
In Ihrem Fall möchten Sie wahrscheinlich von einem Wörterbuch (erhalten mit
json.loads
) zu einem komplexen Objektresponse.education ; response.name
mit einer verschachtelten Strukturresponse.education.id
usw. transformieren. Genau dafür ist dieses Framework gemacht. Die Dokumentation ist noch nicht großartig, aber wenn Sie sie verwendenany2any.simple.MappingToObject
, sollten Sie dies sehr einfach tun können. Bitte fragen Sie, ob Sie Hilfe benötigen.quelle
Verbesserung der sehr guten Antwort der Lovasoa.
Wenn Sie Python 3.6+ verwenden, können Sie Folgendes verwenden:
pip install marshmallow-enum
undpip install marshmallow-dataclass
Es ist einfach und typsicher.
Sie können Ihre Klasse in einen String-JSON umwandeln und umgekehrt:
Vom Objekt zum String Json:
Vom String Json zum Objekt:
Klassendefinitionen:
quelle
Da niemand eine Antwort wie meine gegeben hat, werde ich sie hier posten.
Es ist eine robuste Klasse, die leicht zwischen json hin und her konvertieren kann
str
unddict
die ich aus meiner Antwort auf eine andere Frage kopiert habe :quelle
Ändern der @ DS-Antwort ein wenig, um sie aus einer Datei zu laden:
Eine Sache: Dies kann keine Elemente mit Nummern vor laden. So was:
Weil "1_first_item" kein gültiger Python-Feldname ist.
quelle
Bei der Suche nach einer Lösung bin ich auf diesen Blog-Beitrag gestoßen: https://blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/
Es verwendet die gleiche Technik wie in den vorherigen Antworten angegeben, jedoch unter Verwendung von Dekorateuren. Eine andere Sache, die ich nützlich fand, ist die Tatsache, dass sie am Ende der Deserialisierung ein typisiertes Objekt zurückgibt
Verwendungszweck:
quelle
Wenn Sie die Antwort von DS ein wenig erweitern möchten, müssen Sie die Recordclass- Bibliothek anstelle von namedtuple verwenden , wenn das Objekt veränderbar sein soll (was benanntes Tupel nicht ist) :
Das geänderte Objekt kann dann mit simplejson sehr einfach wieder in json konvertiert werden :
quelle
Wenn Sie Python 3.6 oder höher verwenden , können Sie sich Squema ansehen - ein leichtes Modul für statisch typisierte Datenstrukturen. Es macht Ihren Code einfach zu lesen und bietet gleichzeitig eine einfache Datenvalidierung, -konvertierung und -serialisierung ohne zusätzlichen Aufwand. Sie können sich das als eine ausgefeiltere und einfühlsame Alternative zu Namedtuples und Datenklassen vorstellen. So können Sie es verwenden:
quelle
Ich suchte nach einer Lösung, die funktioniert
recordclass.RecordClass
, verschachtelte Objekte unterstützt und sowohl für die JSON-Serialisierung als auch für die JSON-Deserialisierung funktioniert.Als ich die Antwort von DS und die Lösung von BeneStr erweiterte, fand ich Folgendes, das zu funktionieren scheint:
Code:
Verwendungszweck:
quelle
Die hier gegebenen Antworten geben nicht den richtigen Objekttyp zurück, daher habe ich diese Methoden unten erstellt. Sie schlagen auch fehl, wenn Sie versuchen, der Klasse weitere Felder hinzuzufügen, die im angegebenen JSON nicht vorhanden sind:
quelle
Python3.x
Der beste Ansatz, den ich mit meinem Wissen erreichen konnte, war dieser.
Beachten Sie, dass dieser Code auch set () behandelt.
Dieser Ansatz ist generisch und benötigt nur die Erweiterung der Klasse (im zweiten Beispiel).
Beachten Sie, dass ich es nur mit Dateien mache, aber es ist einfach, das Verhalten nach Ihrem Geschmack zu ändern.
Dies ist jedoch ein CoDec.
Mit etwas mehr Arbeit können Sie Ihre Klasse auf andere Weise aufbauen. Ich gehe davon aus, dass ein Standardkonstruktor es instanziiert, und aktualisiere dann das Klassendiktat.
Bearbeiten
Mit etwas mehr Forschung habe ich einen Weg gefunden, ohne die Notwendigkeit des Aufrufs der SUPERCLASS- Registermethode unter Verwendung einer Metaklasse zu verallgemeinern
quelle
Sie können verwenden
wo
Für eine generische, zukunftssichere Lösung.
quelle
Verwenden Sie das
json
Modul ( neu in Python 2.6 ) oder dassimplejson
Modul, das fast immer installiert ist.quelle