Generelles Vorgehen beim Programmieren

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.
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

danke Blackjack,

also instanziere ich Players über den return-Wert der Klassenmethode?! Macht man das generell so bei Klassen, wo man Daten einlädt?

Und in die JSON Datei fliesst ein Dict mit einem Key "players" und als Value eine Liste mit den Player-Objekten, die in to_dict() in JSON-Strings umgewandelt werden?! Hab ich das richtig verstanden?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Man macht das, weil man es ermoeglichen will, ein Players-Objekt auch so zu konstruieren. Ohne das da gleich ein dicker Lade-Mechanismus anspringt, fuer den man eine Menge an Randbedingungen erfuellen muss. So koennte man zB spaeter auch eine SQLite DB benutzen, oder die Klasse fuer Tests ohne alles instantiieren.

Und ich denke mal du hast das richtig verstanden. Denn so steht's ja auch in BJs code.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

nein, von außen sieht es so aus, als ob Du eine Instanz der Klasse erzeugst, indem Du eine Klassenmethode aufrufst. Klassenmethoden helfen, wenn man verschiedene Arten hat, wie man Instanzen erzeugen könnte.

Das Umwandeln in einen String findet erst bei `json.dump` statt.
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

__blackjack__ hat geschrieben: Freitag 16. August 2019, 12:39 @schnickalot: Da muss man schon etwas mehr machen, denn das funktioniert ja nur wenn man ausschliesslich Werte hat, deren Typ vom JSON-Modul standardmässig in JSON-Werte umwandeln kann und nicht mit beliebigen Datentypen. Das JSON-Modul wüsste nicht was es beim Speichern mit einem `Player`-Objekt machen sollte. Und beim laden werden aus JSON-Daten auch nicht einfach so `Player`-Objekte. Da braucht man in beide Richtungen jeweils mindestens einen Zwischenschritt der Python-Objekte in eine ”JSON-kompatible” Struktur überführt die man dann speichern kann, und die JSON-Datenstruktur die man geladen hat, wieder in Python-Objekte.
Dann wird die "JSON-kompatible" Struktur in to_dict() erstellt? Wenn ja, wie muss das aussehen?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

`to_dict` muß ein Wörterbuch zurückliefern, dessen Schlüssel Strings sind und die Werte nur aus String, Int, Float, oder Listen und Wörterbücher, die diese Grunddatentypen enthalten, bestehen.
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

ok danke.. also muss jedes Attribut, welches Daten hat, die ich speichern möchte, in ein erneutes dict geschrieben werden?

Mal ganz billig so?:

Code: Alles auswählen

def to_dict(self):
    dict = {}
    dict["first_name"] = self.first_name
    dict["last_name"] = self.last_name
    dict["team"] = self.team.name
    dict["games_won"] = self.games_won
    dict["games_lost"] = self.games_lost
    dict["frames_won"] = self.frames_won
    dict["frames_lost"] = self.frames_lost
return dict

So sieht meine Player-Klasse aus:

Code: Alles auswählen

class Player:

    def __init__(self, first_name, last_name, team):
        self.first_name = first_name
        self.last_name = last_name
        self.team = team

        self.score = 0

        self.games_won = 0
        self.games_lost = 0
        self.frames_won = 0
        self.frames_lost = 0

        @property
        def full_name(self):
            return "{} {}".format(self.first_name, self.last_name)

        @property
        def games_total(self):
            return self.games_won + self.games_lost

        @property
        def frames_total(self):
            return self.frames_won + self.frames_lost
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

dict solltest du das nicht nennen, denn so heisst der Typ. Und ein bisschen umstaendlich machst du das auch. Einfacher:

Code: Alles auswählen

def to_dict(self):
    return dict(
        first_name=self.first_name,
        frames_lost=self.frames_lost,
        ...
    )
ACHTUNG: ich BENUTZE dict, den Typ, als Konstruktor. Einen Namen hat das Ding nicht.
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

ok prima. Vielen Dank.

zu from_dict():
Dann return ich dort cls(first_name, last_name, team, games_won=games_won, games_lost=games_lost... und weitere named args, die ich dann auch in der __init__ übergeben muss:

class Player:
def __init__(self, first_name, last_name, team, **kwargs)

richtig?
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze kein **kwargs, sondern gib alle Argumente explizit an.
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

:-) hatte ich schon so da stehen, dachte aber ist professioneller mit **kwargs.

Danke euch allen. Hab's langsam kapiert
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

sorry muss noch mal fragen.. wie genau muss die from_dict() aussehen? Könnt Ihr mir den code mal bitte vorschreiben? Ich steh völlig auf dem Schlauch..
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Du bekommst ein Wörterbuch und übergibst die Werte an die Klasse. Im einfachsten Fall so:

Code: Alles auswählen

class Player:
    def __init__(self, first_name, last_name, team, games_won=0, games_lost=0, ...):
        ....

    @classmethod
    def from_dict(cls, entry):
        return cls(**entry)
Du hast aber nicht den einfachsten Fall, denn die Auflösung von Teamname nach Team muß auch noch in `from_dict` stattfinden:

Code: Alles auswählen

    @classmethod
    def from_dict(cls, entry, teams):
        entry = dict(entry)
        team_name = entry.pop('team_name')
        return cls(team=teams[team_name], **entry)
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

danke.. ich glaub ich versteh nicht wie genau das dict aussieht, weches ich speichere und lade. So wie ich es verstehe habe ich ein Dict mit nur einem Key "players" und als wert wiederum ein Dict, mit den keys first_name. last_name etc und den dazugehörigen Werten.

Visuell mal so dargestellt:

Code: Alles auswählen

"players": "first_name": "Peter",
           "last_name": "Schmidt"
           "team": "BC Buxtehude"
           usw.
Woran ich die ganze Zeit knabber.. so könnte man ja nur einen Player speichern, weil ja in einem Dict nicht 2x der gleiche Key vorhanden sein darf. Also kann es ja keinen 2. Key first_name, last_name etc geben, um die Daten weiterer Spieler zu speichern.

Wo ist denn mein Denkfehler?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das dir eine Liste um die Objekte (so nennt JSON dicts) fehlt. Oder players ist wieder ein dict, und die Schluessel sind die Namen.
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

meinst du das?

data = {
"players": [player.to_dict() for player in self._players.values()]
}

wie sehen denn die Inhalte der ListComprehensive aus? Wahrscheinlich nicht so wie ich es oben dargestellt habe?!
Benutzeravatar
__blackjack__
User
Beiträge: 13080
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich hatte die Player-JSON-Objekte in ein JSON-Array gesteckt, weil der Name sonst ja redundant gespeichert würde.

Wie ein einzelner Player da aussieht bestimmt die `to_dict()`-Methode von `Player`, denn die wird ja für jedes Element in der „list comprehension“ (LC) aufgerufen.

Ansonsten kann man ja auch einfach mal in die gespeicherte JSON-Datei rein schauen wenn man sich das nicht vorstellen kann.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

Ja das ist richtig mir fehlt die Praxis.. bin nur gerade dabei meinen fertigen Anfänger code umzuschreiben. Schwer da was laufbares zu haben. Wollte erstmal die Klassen sauber haben bevor ich die GUI Klassen 3x ändern muss. Ich bau mir heut Abend mal ne Testumgebung auf und schau mir es mal in Detail am. Danke erstmal für die Infos
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

nur mal kurz Rückmeldung.. wenn man sieht was rauskommt, ist dann doch alles klarer. Danke nochmal an alle!
Antworten