Liste von Dictionaries in Liste von Dataklassen

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
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Hallo zusammen,

ich möchte eine Liste von Dictionaries in einer Liste von Klasseninstanzen konvertieren.
Leider habe ich keinen Einfluss auf die Struktur der Eingangsdaten.

Ich habe diese etwas umständliche Lösung gefunden (generisches Beispiel):

Code: Alles auswählen

from dataclasses import dataclass

@dataclass
class Item:
    key: str
    value: str


data = [
    {"key1": "value1"},
    {"key2": "value2"},
    {"key3": "value3"},
]


items = [Item(*next((key,value) for key, value in item.items())) for item in data]
Daher die Frage: Kennt jemand eine Möglichkeit das eleganter zu lösen?
Sirius3
User
Beiträge: 18275
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich wundere mich, wie da die innere for-Schleife herkommt?

Code: Alles auswählen

items = [Item(*next(item.items())) for item in data]
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Sirius3 hat geschrieben: Sonntag 3. Oktober 2021, 12:31 Ich wundere mich, wie da die innere for-Schleife herkommt?
Weil es sonst eine Exception gibt:
'dict_items' object is not an iterator

Ohne innere Schleife ginge das auch noch:

Code: Alles auswählen

items = [Item(*next(iter(item.items()))) for item in data]
Das sieht immer noch umständlich aus.
Sirius3
User
Beiträge: 18275
Registriert: Sonntag 21. Oktober 2012, 17:20

Ja, das ist auch nicht schön. Vielleicht so:

Code: Alles auswählen

[Item(key, value) for item in data for key, value in item.items()]
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Ja, Danke! Ist wahrscheinlich die beste Lösung, so.
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

rogerb hat geschrieben: Sonntag 3. Oktober 2021, 15:51 Ja, Danke! Ist wahrscheinlich die beste Lösung, so.
Ach, ich weiß nicht...

Code: Alles auswählen

[Item(*(d.popitem())) for d in data]
Nur so 'ne Idee. ;-)
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@LukeNukem,

Danke für den Vorschlag. Das ist zwar möglich, wegen des destruktiven Verhaltens, (in diesem Fall) aber nicht anwendbar.

Mal abgesehen davon, ... Ich weiß zwar nicht seit wann es pop() in Python gibt, aber ich kann mir eigentlich nur vorstellen, dass es von Anfang an drin war. Denn als "Sprachverbesserung" wäre es wahrscheinlich immer abgeschmettert worden.
Kennt jemand die Geschichte? Wie findet man eigentlich am schnellsten heraus, wann was zu Python hinzugefügt wurde, ohne sich durch alle Releasenotes lesen zu müssen?
Sirius3
User
Beiträge: 18275
Registriert: Sonntag 21. Oktober 2012, 17:20

@rogerb: bei Dingen, die nicht "schon immer" da waren, findet man in der Dokumentation den Hinweis, ab welcher Version z.B. eine Funktion existiert.
Bei popitem steht die Begründung gleich mit dabei, da sich wohl so manche (wie Du) gefragt haben dürfte, warum es das gibt.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1242
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Das ist nur doof, wenn man anfängt ein dict zu verändern, wenn man es an anderer Stelle ggf. noch benötigt.

So würde ich es machen:

Code: Alles auswählen

from dataclasses import dataclass


@dataclass
class Item:
    key: str
    value: str

    @classmethod
    def from_mapping(cls, mapping):
        return cls(*mapping.copy().popitem())


data = [
    {"key1": "value1"},
    {"key2": "value2"},
    {"key3": "value3"},
]


data2 = [Item.from_mapping(mapping) for mapping in data]
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Sirius3
User
Beiträge: 18275
Registriert: Sonntag 21. Oktober 2012, 17:20

Wenn man schon eine eigene Methode hat, dann ist man ja nicht mehr auf eine Anweisung beschränkt und kann viel verständlicher schreiben:

Code: Alles auswählen

@dataclass
class Item:
    key: str
    value: str

    @classmethod
    def from_mapping(cls, mapping):
        ((key, value), ) = mapping.items()
        return cls(key, value)
Benutzeravatar
DeaD_EyE
User
Beiträge: 1242
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Das ist aber auch nicht viel besser :-D
Bei deinem Code kommt es zu einer Exception, wenn das Dict mehr als ein Key-Value paar hat. Bei meinem Code wird das letzte hinzugefügte Key-Value-Paar ausgegeben, egal wie viele Keys enthalten sind.

Wenn du das so nachbauen willst:

Code: Alles auswählen

@dataclass
class Item:
    key: str
    value: str

    @classmethod
    def from_mapping(cls, mapping):
        *_, (key, value) = mapping.items()
        return cls(key, value)
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Sirius3
User
Beiträge: 18275
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich würde behaupten, das ist ein Vorteil. Bei mehr als einem Key macht die Dataklasse keinen Sinn.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Sirius3 hat geschrieben: Sonntag 10. Oktober 2021, 11:44 Ich würde behaupten, das ist ein Vorteil. Bei mehr als einem Key macht die Dataklasse keinen Sinn.
Einmal das und außerdem ist die ursprüngliche Datenstruktur ja dummerweise eine Liste in der jedes Element aus jeweils nur einem Key-Value-Pair besteht.
Antworten