Object to Json und wieder zurück

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
MichaelM
User
Beiträge: 13
Registriert: Dienstag 15. Dezember 2020, 08:37

Hallo zusammen,

ich finde es toll, wie einfach man ein Object bzw. die Werte als Json String speichern kann. In diesem Zusamenhang hätte ich noch eine Frage:

Zu erst die Klasse mit dem Object:

Code: Alles auswählen

import json
from types import SimpleNamespace
class Konto(object):
    def __init__(self, inhaber, kontonummer,kontostand): 
        self.inhaber = inhaber 
        self.kontonummer = kontonummer 
        self.kontostand = kontostand
        
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

Die Konvertierung in einen Json String:

Code: Alles auswählen

mein_konto=Konto('Max Mustermann','08154711',11.25)
j_son=mein_konto.toJSON()
print(j_son)
Führt zur folgenden Ausgabe:

Code: Alles auswählen

{
    "inhaber": "Max Mustermann",
    "kontonummer": "08154711",
    "kontostand": 11.25
}
Also wie gewünscht.
Nun möchte ich die daten in einer Datei im Json Format speichern.
Frage: Wie bekomme ich die Daten rückwärts wieder als ein Object Konto, mit den Daten?
Ich bekomme die Daten zurück in ein Object:

Code: Alles auswählen

from collections import namedtuple
x=json.loads(j_son, object_hook=lambda d: namedtuple('x', d.keys())(*d.values()))
print (x.inhaber)
type(x)
x beinhaltet alle Daten, soweit so gut. Ich hätte aber gern wieder den Bezug zu meiner Klasse Konto hergestellt.

Vielen Dank vorab!
Sirius3
User
Beiträge: 18227
Registriert: Sonntag 21. Oktober 2012, 17:20

Du mußt ja schon eine Instanz Deiner Klasse herstellen. In den Daten steht ja nirgends, wo die Daten ursprünglich gespeichert waren.

Code: Alles auswählen

j_son = '''{
    "inhaber": "Max Mustermann",
    "kontonummer": "08154711",
    "kontostand": 11.25
}'''
konto = Konto(**json.loads(j_son))
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und wenn du mehrere Objekte unterschiedlicher Art in deinem JSON hast, musst du ggf. weitere Schritte unternehmen: zb kann man ein weiteres Attribut für den Typ definieren. Und anhand dessen die Klasse bestimmen, die man mit den Daten erzeugt. Oder es basiert auf bestimmten Pfaden. Also alles was users.$number.account ist, wäre ein Konto. Und users.$number ist ein User.
MichaelM
User
Beiträge: 13
Registriert: Dienstag 15. Dezember 2020, 08:37

Das ist Klase, danke, geht so etwas auch von einem dict? Also sozusagen als Umkehr von

Code: Alles auswählen

__dict__
?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Die Frage verstehe ich nicht.
MichaelM
User
Beiträge: 13
Registriert: Dienstag 15. Dezember 2020, 08:37

Oh das ware ich auch etwas schnell- sorry.

Wenn ich mehere Konten in ein Json File speichern möchte, sah es mir am einfachsten aus, vorher eine Liste mit Dicts zu erstellen und diese Liste dann in einen Json String zu konvertieren.:

Code: Alles auswählen

mein_konto=Konto('Max Mustermann','08154711',11.25)
dein_konto=Konto('Lisa Müller','47110815',103.55)


Kontoliste=[]
Kontoliste.append(mein_konto.__dict__)
Kontoliste.append(dein_konto.__dict__)

json_string=json.dumps(Kontoliste,indent=4)
Wenn ich den json String dann wieder lade, hätte ich ja wieder eine Liste mit den dicts der zwei Konten:

Code: Alles auswählen

Kontoliste_neu=json.loads(json_string)

print(Kontoliste_neu)
Kann man diese auch wieder jeweils in ein Object Konto "konvertieren"?
MichaelM
User
Beiträge: 13
Registriert: Dienstag 15. Dezember 2020, 08:37

Ich sehe, es war zu einfach:

Code: Alles auswählen

x=Konto(**Kontoliste[0])
Und ich habe mein gewünschtes Object.

Vielen Dank für die Unterstützung!
Benutzeravatar
__blackjack__
User
Beiträge: 13937
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@MichaelM: Anmerkungen zu den Quelltexten:

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase). Also `to_json()` statt `toJSON()` und `kontoliste` statt `Kontoliste.

Allerdings: Grunddatentypen haben nichts in Namen verloren. Den Typen ändert man gar nicht so selten mal während der Programmentwicklung und dann muss man überall im Programm die betroffenen Namen ändern, oder man hat falsche, irreführende Namen im Quelltext. Also statt `kontoliste` einfach nur `konten`. Oder `accounts`. Englisch hat den Vorteil, dass es dort wesentlich seltener Vorkommt, dass die Einzahl genau wie die Mehrzahl geschrieben wird und man da nicht so oft das Problem hat sich überlegen zu müssen wie man in solchen Fällen einzelne Elemente einer Liste und die Liste selbst nennen soll.

Eine leere Liste erstellen um dann direkt danach einzelne Elemente mit `append()` hinzuzufügen ist ziemlich umständlich. Man kann die Elemente doch gleich in das Listenliteral schreiben:

Code: Alles auswählen

    konten = []
    konten.append(mein_konto.__dict__)
    konten.append(dein_konto.__dict__)
    
    # =>
    
    konten = [mein_konto.__dict__, dein_konto.__dict__]
Die Konten dann einzeln mit einem festen Index aus dem deserialisierten JSON-Array zu holen skaliert nicht. Da würde man gleich alle Kontendaten in eine Liste mit Kontoobjekten umwandeln:

Code: Alles auswählen

    konten = [Konto(**konto_daten) for konto_daten in konten_daten]
Wobei das ganze mit dem `__dict__` (wo man eher nicht von aussen drauf zugreifen sollte) und dem ``Class(**json_object_data)``-Muster nur für einfache Fälle funktioniert.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
MichaelM
User
Beiträge: 13
Registriert: Dienstag 15. Dezember 2020, 08:37

@__blackjack__: Vielen Dank für die Hinweise.
Antworten