Ich versuche, eine JSON-Zeichenfolgendarstellung einer Klasseninstanz zu erstellen, und habe Schwierigkeiten. Angenommen, die Klasse ist folgendermaßen aufgebaut:
class testclass:
value1 = "a"
value2 = "b"
Ein Aufruf von json.dumps erfolgt wie folgt:
t = testclass()
json.dumps(t)
Es schlägt fehl und sagt mir, dass die Testklasse nicht JSON-serialisierbar ist.
TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable
Ich habe auch versucht, das Gurkenmodul zu verwenden:
t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))
Und es gibt Klasseninstanzinformationen, aber keinen serialisierten Inhalt der Klasseninstanz.
b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'
Was mache ich falsch?
python
json
serialization
pickle
Ferhan
quelle
quelle
s = json.dumps(obj, default=lambda x: x.__dict__)
, serialisiert Objektinstanzvariablen (self.value1
,self.value2
, ...). Es ist der einfachste und direkteste Weg. Verschachtelte Objektstrukturen werden serialisiert. Diedefault
Funktion wird aufgerufen, wenn ein bestimmtes Objekt nicht direkt serialisierbar ist. Sie können sich auch meine Antwort unten ansehen. Ich fand die populären Antworten unnötig komplex, was wahrscheinlich schon vor langer Zeit zutraf.testclass
haben keine__init__()
Methode, daher teilen alle Instanzen dieselben zwei Klassenattribute (value1
undvalue2
), die in der Klassenanweisung definiert sind. Verstehst du den Unterschied zwischen einer Klasse und einer Instanz von einer?Antworten:
Das Grundproblem besteht darin, dass der JSON-Encoder
json.dumps()
nur eine begrenzte Anzahl von Objekttypen serialisieren kann, standardmäßig alle integrierten Typen. Liste hier: https://docs.python.org/3.3/library/json.html#encoders-and-decodersEine gute Lösung wäre, Ihre Klasse von
JSONEncoder
derJSONEncoder.default()
Funktion erben zu lassen und diese dann zu implementieren und diese Funktion den richtigen JSON für Ihre Klasse ausgeben zu lassen.Eine einfache Lösung wäre,
json.dumps()
das.__dict__
Mitglied dieser Instanz aufzurufen . Das ist ein Standard-Pythondict
und wenn Ihre Klasse einfach ist, ist sie JSON-serialisierbar.Der obige Ansatz wird in diesem Blogeintrag erläutert:
Serialisierung beliebiger Python-Objekte in JSON mithilfe von __dict__
quelle
.__init__()
Methodenfunktion hat, sodass Ihre Klasseninstanz ein leeres Wörterbuch hat. Mit anderen Worten,{}
ist das richtige Ergebnis für Ihren Beispielcode.is not JSON serializable
Es gibt einen Weg, der für mich großartig funktioniert und den Sie ausprobieren können:
json.dumps()
kann einen optionalen Parameter als Standard verwenden, in dem Sie eine benutzerdefinierte Serializer-Funktion für unbekannte Typen angeben können, die in meinem Fall so aussiehtDie ersten beiden ifs beziehen sich auf die Serialisierung von Datum und Uhrzeit, und dann wird
obj.__dict__
für jedes andere Objekt eine Rückgabe zurückgegeben.Der letzte Anruf sieht aus wie:
Dies ist besonders gut, wenn Sie eine Sammlung serialisieren und nicht
__dict__
für jedes Objekt explizit aufrufen möchten . Hier wird es automatisch für Sie erledigt.Bisher hat es so gut für mich funktioniert und ich freue mich auf deine Gedanken.
quelle
NameError: name 'serialize' is not defined
. Irgendwelche Tipps?try: dict = obj.__dict__ except AttributeError: dict = {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)} return dict
Sie können den
default
benannten Parameter in derjson.dumps()
Funktion angeben :Erläuterung:
Bilden Sie die Dokumente ( 2.7 , 3.6 ):
(Funktioniert mit Python 2.7 und Python 3.x)
Hinweis: In diesem Fall benötigen Sie
instance
Variablen und keineclass
Variablen, wie im Beispiel in der Frage versucht. (Ich gehe davon aus, dass der Fragestellerclass instance
ein Objekt einer Klasse sein soll)Ich habe dies zuerst aus der Antwort von @ phihag hier gelernt . Ich fand es die einfachste und sauberste Art, die Arbeit zu erledigen.
quelle
default=lambda x: getattr(x, '__dict__', str(x))
datetime.date
ist eine C-Implementierung, daher hat sie kein__dict__
Attribut. IMHO aus Gründen der Einheitlichkeitdatetime.date
sollte es sein ...Ich mache einfach:
Dies ist nicht die vollständige Antwort, und wenn Sie eine komplizierte Objektklasse haben, werden Sie sicherlich nicht alles bekommen. Ich benutze dies jedoch für einige meiner einfachen Objekte.
Eine, bei der es sehr gut funktioniert, ist die Klasse "options", die Sie vom OptionParser-Modul erhalten. Hier ist es zusammen mit der JSON-Anfrage selbst.
quelle
Mit jsonpickle
quelle
JSON ist nicht wirklich zum Serialisieren beliebiger Python-Objekte gedacht. Es eignet sich hervorragend zum Serialisieren von
dict
Objekten, aber daspickle
Modul ist genau das, was Sie im Allgemeinen verwenden sollten. Die Ausgabe vonpickle
ist nicht wirklich lesbar, sollte sich aber problemlos lösen. Wenn Sie darauf bestehen, JSON zu verwenden, können Sie sich dasjsonpickle
Modul ansehen, das ein interessanter hybrider Ansatz ist.https://github.com/jsonpickle/jsonpickle
quelle
Hier sind zwei einfache Funktionen für die Serialisierung von nicht hoch entwickelten Klassen, nichts Besonderes, wie zuvor erläutert.
Ich verwende dies für Konfigurationsarten, da ich den Klassen ohne Code-Anpassungen neue Mitglieder hinzufügen kann.
quelle
Es gibt einige gute Antworten, wie Sie damit beginnen können. Es gibt jedoch einige Dinge zu beachten:
__slots__
anstelle von verwenden__dict__
?json-Tricks ist eine Bibliothek (die ich erstellt habe und zu der andere beigetragen haben), die dies schon seit einiger Zeit kann. Beispielsweise:
Sie erhalten Ihre Instanz zurück. Hier sieht der json so aus:
Wenn Sie Ihre eigene Lösung erstellen möchten, können Sie sich die Quelle ansehen
json-tricks
, um einige Sonderfälle (wie__slots__
) nicht zu vergessen .Es werden auch andere Typen wie Numpy-Arrays, Datumsangaben und komplexe Zahlen ausgeführt. es erlaubt auch Kommentare.
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 Recherche habe ich einen Weg gefunden, ohne die Notwendigkeit des Aufrufs der SUPERCLASS- Registermethode mithilfe einer Metaklasse zu verallgemeinern
quelle
Ich glaube, anstelle der Vererbung, wie in der akzeptierten Antwort vorgeschlagen, ist es besser, Polymorphismus zu verwenden. Andernfalls müssen Sie eine große if else-Anweisung haben, um die Codierung jedes Objekts anzupassen. Das bedeutet, dass Sie einen generischen Standardcodierer für JSON erstellen als:
und haben dann eine
jsonEnc()
Funktion in jeder Klasse, die Sie serialisieren möchten. z.BDann rufst du an
json.dumps(classInstance,default=jsonDefEncoder)
quelle