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.
CasualCoding.org

Samstag 11. August 2012, 10:37

Hallo Forum!

Ich bin in meinem Privatleben begeisterter Linux-Nutzer und interessiere mich darüber hinaus sehr fürs Programmieren. Es macht mir wirklich viel Spaß, und ich habe so einige Projektideen im Hinterkopf, die ich gern mal irgendwann umsetzen würde. Aber ich stoße immer wieder auf dasselbe, für mich wirklich große Problem. Ich habe eine zeitlang sehr intensiv Java gelernt, ich habe mich in den letzten Jahren immer und immer wieder mal mit C und C++ beschäftigt, und jetzt gerade arbeite ich zum zweiten Mal das Python-Buch von Michael Weigend durch.

Mein Problem ist nicht das Erlernen der Syntax und der Konzepte einer Sprache an sich. Ich habe wenige Verständnisprobleme bei den einzelnen Kapiteln meiner Lehrbücher, ich verstehe die ganzen Codebeispiele, ich weiß, warum die Autoren wann was machen, und auch die Übungsaufgaben bereiten mir meist wenig Probleme.

Woran es dann aber regelmäßig hängt, ist die Umsetzung in eigene, reale Projektideen. Das Zusammenfügen der einzelnen Aspekte zu einem Ganzen. Ich kann nicht einmal genau beschreiben, wo konkret mein Problem liegt, sondern ich stehe einfach vor einem großen Haufen offener Fragen und weiß nicht, wo ich ansetzen soll. Und zwischen den Einstiegs-Lehrbüchern mit ihren Minibeispielen, sowie den Mini-Übungsaufgaben auf den einschlägigen Webseiten einerseits und dem Studieren von realem Code andererseits liegt für mich eine Lücke, die ich einfach nicht überwunden bekomme.

Ich bin diesbezüglich wirklich ratlos. Helfen Bücher wie die eher theoretischen der Head-First-Reihe ("Softwareentwicklung", "Programmierung", etc.)? Ist es sinnvoll, einfach irgendwas zusammenzuschustern, egal wie grauenhaft und unübersichtlich es ist, und es hier auseinander nehmen zu lassen?

Ich weiß wirklich nicht, wie ich an diesem entscheidenden Punkt weiterkommen soll und wäre für Tipps sehr dankbar.
Benutzeravatar
snafu
User
Beiträge: 5992
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Samstag 11. August 2012, 11:01

Du hast anscheinend Probleme, die nötige Struktur in dein Denken reinzubekommen. Das kann man IMHO nur durch viel Übung mittels praktischen Umsetzungen (also Code-Schreiben) erlernen. Du kannst gerne deinen "grauenhaften" Code zur Beurteilung ins Forum stellen. Hier finden sich eigentlich immer ein paar Leute, die sich die Zeit nehmen, gepostete Schnipsel durchzugehen und zu kommentieren.

Achso, und dir fehlt wahrscheinlich auch generell die Routine, um zu wissen, wie man eine Aufgabe am Besten mit den Möglichkeiten der Sprache umsetzen kann. Auch hier gilt wieder: Learning by Doing.
CasualCoding.org

Samstag 11. August 2012, 12:19

Erstmal danke für deine Antwort. Aber ja, das ist der Standard-Tipp, den ich auch vollkommen verstehe; nur weiß ich eben gar nicht, wo ich ansetzen soll.

Machen wir es konkret: Eines meiner größten Wunschprojekte ist die Umsetzung eines Würfelspiels, das ich aus meinen Barkeeper-Tagen kenne. Ich habe da für den Anfang gar keine großen Visionen. Es muss erstmal keine GUI haben und auch keine tausend Einstellungen und Optionen. Einfach erstmal den grundsätzlichen Spielablauf für einen menschlichen Spieler gegen, sagen wir, drei Computerspieler auf der Konsole.

Eine schöne Spielerklasse bekomme ich wahrscheinlich noch hin, also nicht nur irgendwie, sondern sogar halbwegs akzeptabel und für die jeweilige Sprache einigermaßen idiomatisch. Aber dann sitze ich vor meiner Spielerklasse und weiß nicht, wie ich von da aus weitermachen soll. Da sind dann einfach nur Fragezeichen.

Nehmen wir ein ganz einfaches Würfelspiel. Wie wäre denn deine Herangehensweise an sowas?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7477
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Samstag 11. August 2012, 12:52

SolitaryMan hat geschrieben: Nehmen wir ein ganz einfaches Würfelspiel. Wie wäre denn deine Herangehensweise an sowas?
Naja, Du hast bei einem Spiel ja Spielregeln - bei jedem Gesellschaftsspiel, das man kauft, ist doch letztlich eine Beschreibung des Ablaufs und der Regeln dabei. Das ist letztlich in Prosa ein Algorithmus für das Spiel. Diese Angaben muss man nun eben mit den Mitteln einer Programmiersprache umsetzen.

Du musst Dir eben überlegen, was für Objekte Du benötigst und wie diese interagieren. Dann kommt da noch ein Ablauf rein, also idR. eine Schleife, in der so lange verweilt wird, bis das Spiel zu Ende ist (also vermutlich eine Siegbedingung eingetroffen ist o.ä.).

Wo genau liegt da jetzt eine konkrete Schwierigkeit? Man kann hier nur allgemein bleiben, weil das eben die Essenz des Programmierens ist - genau dieses Vorgehen macht den kreativen Prozess beim Entwickeln aus. Das kann man nur lernen, indem man sich selber daran versucht und die Gedankengänge und Vorgehensweisen anderer analysiert und nachvollzieht.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 5992
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Samstag 11. August 2012, 14:41

SolitaryMan hat geschrieben:Eine schöne Spielerklasse bekomme ich wahrscheinlich noch hin, also nicht nur irgendwie, sondern sogar halbwegs akzeptabel und für die jeweilige Sprache einigermaßen idiomatisch. Aber dann sitze ich vor meiner Spielerklasse und weiß nicht, wie ich von da aus weitermachen soll. Da sind dann einfach nur Fragezeichen.

Nehmen wir ein ganz einfaches Würfelspiel. Wie wäre denn deine Herangehensweise an sowas?
Naja, Objekte haben Eigenschaften und Fähigkeiten. Konkret gesagt könnte eine Eigenschaft von Würfelspielern sein, dass sie einen Punktestand haben. Eine Fähigkeit wäre das Würfeln: `Player.throw_dice()` (oder sowas ähnliches). Eine Art Spielverwaltung (als eigene Klasse) weiß, wer aktuell an der Reihe ist und ruft die Würfel-Methode des passenden Spielers auf. Auch könnte man eine Art Regelprüfer implementieren, der darauf achtet, dass ein Spieler z.B. nur 3 mal würfeln darf. Bei Verstößen wird eine Ausnahme (etwa: `IllegalActionError`) geworfen, usw. Die zuvor genannte Spielverwaltung (`Game`) könnte jetzt mit einem bestimmten Regelprüfer und einer Liste von Spieler-Objekten initialisiert werden. Mittels `game.play()` würde eine Schleife gestartet werden, die den Spielbeginn einleitet. Es gäbe für den Anfang sicher nur einen Regelprüfer (`Rules`), aber vielleicht möchte man später weitere Regel-Klassen implementieren, um Abwandlungen spielen zu können. Auch Spieler könnten gewisse gemeinsame Funktionalität in einer Basisklasse haben und dann in abgeleiteter Form in menschliche oder computergesteuerte Spieler unterteilt werden. Die Computerspieler-Intelligenz wiederum wäre auch als eigene Klasse mit Raum für Erweiterungen (vielleicht sogar als Plugins) denkbar.

Also mir fällt hier jede Menge ein, was man theoretisch machen könnte. Wichtig ist es aber, zunächst einmal mit eher simpel gehaltenen Strukturen anzufangen, damit man sich nicht völlig in der Planung verliert. Später kann ja bei Bedarf immer noch Refactoring des Codes betrieben werden. Einiges will man vielleicht auch erstmal als simple Option/Flag einbauen (z.B. `Player.__init__(self, human=True)`). Wichtig ist, dass irgendwann etwas da ist, was man tatsächlich starten kann. Und danach kann halt beliebig weitergemacht werden. Je nach persönlicher Motivation und Zeit natürlich.

Da du sagstest, dass du besonders Java intensiver gelernt hast, denke ich mal, dass ich dir teilweise nichts wirklich Neues erzählt habe. Allerdings lässt sich deine Fragestellung anders auch nicht beantworten.
CasualCoding.org

Samstag 11. August 2012, 14:58

snafu hat geschrieben:Da du sagstest, dass du besonders Java intensiver gelernt hast, denke ich mal, dass ich dir teilweise nichts wirklich Neues erzählt habe. Allerdings lässt sich deine Fragestellung anders auch nicht beantworten.
Naja, doch, ein Stückchen hast du mir schon weiter geholfen. Die Idee zu einer Spielverwaltungsklasse hätte ich zum Beispiel auch gehabt - aber das Zusammenfügen der Einzelteile, das wäre jetzt schon wieder mein Problem gewesen. Hier liegen vielleicht einfach auch Defizite vor, was das Verständnis von Objektorientierung angeht - eigentlich ist deine geschilderte Idee, einer Spielverwaltungsinstanz Spielerobjekte und ein Regelüberwachungsobjekt als Argumente zu übergeben und in einer Schleife ihre Arbeit tun zu lassen, nämlich sehr simpel.

Aber wenn ich vor meinen Projektideen sitze und meinen Klassencode vor mir habe, bin ich urplötzlich ratlos und völlig blockiert für sowas. Noch schlimmer wird es dann, wenn eine GUI und damit eine zusätzliche "Schicht" dazu kommt. Ein paar kleinere Sachen hatte ich in Java durchaus hinbekommen, aber danach eine Swing-GUI davor zu setzen, ging dann schon wieder komplett schief.
Benutzeravatar
snafu
User
Beiträge: 5992
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Samstag 11. August 2012, 15:24

Und wie gesagt: Nimm dir nicht zuviel auf einmal vor. Man könnte ja erstmal ein Spiel mit Phantasie-Regeln schreiben, wo es nur darum geht, mit 3 Würfeln mindestens 10 Punkte zu erzielen, wobei für den Anfang beliebig oft wiederholt werden darf, bis eben ein Wurf das Minimum überschritten hat. Die Augenzahl wird dann aufgeschrieben und der nächste Spieler ist dran. Wer als erstes insgesamt 100 Punkte hat, ist der Sieger. Sowas halt. Die Konzentration läge da also auf der Ermittlung einer zufälligen Augenzahl je Würfel (das Modul `random` ist dein Freund), sowie der allgemeinen Spielverwaltung. Für den Anfang könnte die Spiellogik (sprich: die Regeln) ja noch in der `Game`-Klasse implementiert sein und die Spielerstände wären als Dictionary denkbar. Auch die Fehlerbehandlung könnte für den ersten Prototypen erstmal außen vorgelassen werden. Und wenn das alles steht, möchtest du es vielleicht hier präsentieren und dann machste weiter, damit der Spielverlauf komplexer wird und Verbesserungsvorschläge einfließen können.
mcdwerner
User
Beiträge: 113
Registriert: Donnerstag 7. Juli 2011, 14:27

Montag 13. August 2012, 09:40

@ SolitaryMan:

hier: http://www.udacity.com/view#Course/cs21 ... get/294001 wird der Entwurf eines Würfel-Spiels recht kleinschrittig und anschaulich gezeigt.

bin mittlerweile ein großer Fan von Udacity geworden...
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

Dienstag 13. August 2019, 16:22

Hallo zusammen,

der Thread ist ja schon einiges her, aber TE's Denk-Probleme kommen mir sehr bekannt vor. Ich bin auch ein Typ der 2-3 Sprachen per Anfänger Bücher durch hat, aber die Praxis ist dann doch "anders".. besonders mit eigenen Programmwünschen (Ich kann fib() nicht mehr sehen!).

Ich habe vor, einen Snooker Scorer zu schreiben. Speziell für Liga-Spieltage. Sinn ist eine Art Anzeigetafel im Billardclub zu haben wo die einzelnen Partien mitgescored werden.
Kurze Skizze des Hauptfensters:

Match Home Score Away
1 Klaus 0 (7) 0 Martin
2 Hans 0 (7) 0 Friedrich
3 Mike 0 (7) 0 Horst
4 Norbert 0 (7) 0 Andreas
5 Falk 0 (7) 0 Thomas
6 Stefan 0 (7) 0 Christian

Gespielt werden 6 Matches je best-of-7-Frames (1 Frame ist wie ein Spiel). Immer wenn ein Spieler ein Frame gewinnt, soll zu seinem Score +1 gerechnet werden. Eine Match ist vorbei wenn ein Spieler 4 Frames gewonnen hat. Die ganze Partie ist vorbei, wenn alle 6 Matches fertig sind (kann am Ende des Tages also auch 3-3 ausgehen).

Folgende Klassen habe ich erstellt:
Player (Attribute "Firstname", "Lastname", "Fullname", "Teamname", "Score")
Playerlist (erbt von Dict und speichert alle Playerinstanzen (Dict-Key = Fullname), welche auch per pickle in eine Datei gesichert und bei Programmstart geladen werden)

Team (Attribute "Name" und [Roster] (für die Aufstellung)) -> in der Liste "Roster" will ich alle Playerobjekte einer Mannschaft zwischenlagern, die zum Spieltag erscheinen und aufgestellt werden. Diese werden dann aus der kompletten Playerlist rausgepickt.
Teamlist (erbt von Dict und speichert alle Teaminstanzen (Dict-Key = Name), welche auch per pickle in eine Datei gesichert und bei Programmstart geladen werden)

-> Um Player und Teams zu managen habe ich bereits GUI-Screens fertig und das anlegen, editieren und löschen funktioniert prima. (Screens, weil ich auf Enigma2-TV-Boxen Python lerne)

Weitere Klassen:
Game (Attribute "Totalframes", "Winframe" (Totalframes // 2 + 1), "Hometeam", "Awayteam", [Matches]) -> Hometeam, Awayteam werden mit Teamobjekten belegt. In [Matches] sollen alle 6 Matchinstanzen liegen.

Match (Attribute "Homeplayer", "Awayplayer") -> Homeplayer, Awayplayer werden mit Playerobjekten belegt, die aus der Liste "Roster" nach einem festen Schema rausgepickt werden (Gespielt wird über Kreuz, also 1 gegen 2, 2 gegen 3, 3 gegen 1 usw.)

Ich hoffe es ist einigermassen verständlich. Jetzt zu meiner eigentlichen Frage:
Geht man so mit Klasseninstanzen um? zB die Playerinstanzen: Beim erstellen landen sie in der Playerlist und werden weggespeichert. Beim Spieltag werden sie dann in die Liste "Roster" eines Teams gesteckt, um sie danach einem Match-Attribut zuzuweisen. Dort wird der Score gepflegt und am Ende will ich eigentlich noch Statistiken speichern, wie zB "gespielte Matches", "gewonnene Matches, "verlorene Matches". Die Playerinstanz muss dann also auch wieder zurück in die Playerlist und gespeichert werden, damit die Statistiken nicht verloren gehen. Der laufende Score fängt jedes mal bei Null an und ist natürlich nicht wichtig zu speichern.
Oder lässt man Instanzen in der Liste (in meinem Fall die Playerlist) und spricht sie nur da an, ohne sie anderen Attributen oder Listen zuzuweisen?
Benutzeravatar
__blackjack__
User
Beiträge: 4663
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 13. August 2019, 19:12

@schnickalot: Bei den Attributnamen hälst Du Dich anscheinend nicht an die Namenskonventionen. klein_mit_unterstrichen für alles ausser Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Was ist `Player.full_name`? Ist das wirklich eigenständig oder kann man das aus `Player.firstname` und `Player.surname` ”berechnen”? Dann wär's eher ein `property()` statt eines normalen Attributs.

`Playerlist`: Grunddatentypen haben nichts in Namen zu suchen. Und schon mal gar nicht wenn das dann auch noch von einem ganz anderen Grunddatentyp erbt. Wobei man von Grunddatentypen auch eher nicht erbt, weil die ganzen Methoden die man sich damit einfängt in der Regel gar nicht alle sinnvoll auf den neuen Datentyp anwendbar sind. Was hat denn Dein `Playerlist` denn an anderem Verhalten als ein `dict`? Brauchst Du da überhaupt einen eigenen Datentyp für?

`pickle` ist für längerfristige Datenspeicherung ungeeignet, weil das nur schlecht bis gar nicht mit Änderungen am Code klar kommt die Einfluss auf die Codeaufteilung und die Namensgebung haben. Zudem ist das auf Python beschränkt. Daten serialisiert man besser explizit in einem Standardformat. JSON bietet sich oft an.

Für `Teamlist` gilt das gleiche.

Die eigentliche Frage am Ende verstehe ich nicht so ganz beziehungsweise scheint die so ein bisschen auf ein Missverständnis auf Deiner Seite hinzudeuten. Eine `Player`-Objekt das Du aus `Playerlist` holst und dann dem `roster` von einem `Team` hinzufügst muss nicht „zurück in die Playerlist“, ausser Du entfernst das aus der `Playerlist` tatsächlich – wo ich keinen Grund für sehe das zu machen.

Man lässt die `Player` sowohl in der `Playerlist` *und* man weist sie anderen Attributen zu oder steckt sie in Listen oder andere Datenstrukturen. Warum sollte man das nicht machen? Das ist ja immer das *selbe* `Player`-Objekt was dann eben über mehrere Wege erreichbar ist. Überall dort wo man den Zugriff braucht.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
Benutzeravatar
snafu
User
Beiträge: 5992
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 13. August 2019, 20:12

Immer wieder interessant, ältere Beiträge von sich zu lesen. Wurde zum Glück nicht peinlich für mich. Ich würde heute sehr ähnlich darauf antworten. :)
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

Dienstag 13. August 2019, 22:01

Vielen Dank Blackjack.. das genau war mein Denkfehler. Ich dachte irgendwie immer das sich Instanzen kopieren wenn ich sie von hier nach dort übergebe.. aber klar.. es sind nur neue Referenzen darauf.

Die Konventionen halte ich ein.. frag mich nicht wieso ich's hier anders getippt habe. Außer die Unterstriche.. denke gelesen zu haben man kann es machen ist aber kein muss.

Die Playerlist war ursprünglich mit einer self.list bestückt bevor ich dict vererbt habe.. deswegen der legacy name. Das man list/dict etc nicht im Namen benutzt wusste ich nicht.. guter Hinweis. Wäre sowas wie PlayerPool, PlayerContainer passender oder evtl. einfach das Plural von den Objekten.. Players? Auf dict habe ich umgestellt um die Player per Key direkt anzusprechen anstatt mit for drüber zu iterieren. Und ja.. der fullname ist ein Gebastel aus firstname Leerzeichen und lastname. Das mit Property zu lösen klingt auch gut.

Danke nochmal.. hoffe ich frag nichts zu peinliches.
Benutzeravatar
__blackjack__
User
Beiträge: 4663
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Dienstag 13. August 2019, 22:51

@schnickalot: Die Unterstriche sind IMHO ein muss. Sonst wird es schwerer den Code zu lesen. Der Unterstrich fungiert ja als Trennzeichen zwischen Worten wie das Leerzeichen in normalen Texten. Wenn man das weg lässt, dann muss der Leser das im Kopf selbst finden und setzen. Und das ist nicht bei allen Kombinationen so einfach, und selbst bei solchen wo es eindeutig ist, kann es passieren das man erst über die Stelle hinweg liest, bevor ein Namenspräfix als einzelnes Wort keinen Sinn mehr macht, und man dann erst wieder ”suchen” muss wo das nächste Wort in dem man schon mitten drin ist, eigentlich anfängt. Blödes Beispiel: `identry` – da kann man bis `ident` lesen, bevor man merkt, das nach `id` eigentlich ein ”Leerzeichen” gehört und eigentlich `id_entry` gemeint ist. Man kann das sogar komplett als ein Wort aussprechen und müsste wenn man sich nicht sicher ist, Nachschlagen ob es nicht tatsächlich eine Bedeutung für das Wort „identry“ gibt und das vielleicht tatsächlich gemeint ist.

Ein Experiment dafür wäre vielleicht mal einen englischsprachigen Text her zu nehmen und da immer zwei bis drei Worte zu ”einem” zusammen zu fassen und dann mal zu schauen wie (un)flüssig sich das dann liest.

Du hast da ja genau das Problem mit Grunddatentypen in Namen getroffen: Im Laufe der Programmentwicklung ändert man solche Datentypen öfter mal, und muss dann überall die betroffenen Namen ändern, oder hat irreführende weil falsche Namen im Quelltext stehen. Es kommt relativ häufig vor, dass man mit einer Liste anfängt und vielleicht irgendwann feststellt, dass man eigentlich ein `set()` möchte weil man keine doppelten Einträge hat, die Reihenfolge egal ist, aber eine schnelle ``in``-Operation gebraucht wird. Oder das man zwar die Reihenfolge braucht, und über die Elemente iteriert, das aber alles war was man von `list` benötigt, dafür hätte man aber gerne andere Methoden die Zugriff auf die Elemente benötigen. Dann kann man die Liste durch einen eigenen Datentyp ersetzen.

Bei der Benennung einfach die Mehrzahl sowohl bei Klassen als auch bei Objekten die als Sammlung von anderen Objekten verwendet werden. Wobei `Players` schon ein bisschen mehr bieten sollte als einfach nur eine Abbildung von Spielernamen auf Spielerobjekte, denn sonst hätte man auch gleich dort wo man ein `Players`-Objekt erstellt, einfach ein `dict` verwenden können.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
schnickalot
User
Beiträge: 22
Registriert: Dienstag 13. August 2019, 14:38

Mittwoch 14. August 2019, 00:24

Ja die Players und Teams Klassen haben noch die pickle Methoden und n paar spezielle Methoden das dict abzufragen.

Nochmals vielen Dank für die Ausführungen. Das macht vieles klarer.

Werde auch mal auf Unterstriche umstellen. Klingt schon vernünftig. Vielleicht noch ein Wort zu kein 1 oder 2 Unterstriche vor dem Attributname.. zZ habe ich 1 Unterstrich davor. Getter und Setter sind zu einem Property (Attributname) zusammengefasst. Passt das so? Ich weiß das 1 Unterstrich eine Konvention darstellt und 2 den internen Namen verbiegen. Aber was nimmt man warum und wann?
Benutzeravatar
__blackjack__
User
Beiträge: 4663
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Mittwoch 14. August 2019, 01:08

@schnickalot: Was machen denn die `pickle`-Methoden? So aus dem Bauch heraus würde ich ja sagen das gehört nur auf das Objekt wenn die Methode irgend etwas für diesen Typ spezifisches macht, ansonsten ist das eher etwas was man von aussen *mit* dem Objekt macht.

Was heisst „Getter und Setter sind zu einem Property […] zusammengefasst“? Was machen die denn spezielles mit dem Wert? Denn in Python schreibt man keine trivialen Getter und Setter weil die keinen Sinn machen, eben weil es `property()` gibt wenn man aus einem einfachen Attribut etwas machen will wo noch zusätzlich etwas passiert wenn man es abfragt und/oder setzt. Und ein `property()` das einfach nur einen Wert abfragt oder setzt und sonst nix macht, macht keinen Sinn. Den Effekt kann man auch mit weniger Code haben.

Ein `Player` einfach erst einmal nur so als Datenklasse könnte man beispielsweise so schreiben:

Code: Alles auswählen

from attr import attrib, attrs


@attrs
class Player:
    first_name = attrib()
    last_name = attrib()
    team_name = attrib(default=None)
    score = attrib(default=0)
    
    @property
    def full_name(self):
        return f'{self.first_name} {self.last_name}'
Wobei ich hier `team_name` wahrscheinlich durch `team` ersetzen würde, statt den Umweg über einen Namen zu gehen.

Beim `Team` könnte es dann interessant werden das Attribut für die Spieler nicht öffentlich zu machen, damit man die Invariante sichern kann, das Spieler beim hinzufügen auch das passende `team` (oder auch `team_name`) Attribut gesetzt bekommen und vielleicht auch das man nur Spieler zu einem Team hinzufügen kann, wenn das Attribut noch den Wert `None` hat.

Und mindestens den Spieler-Objekten würde ich noch eine ID verpassen, denn das Leute mit gleichen Vor- und Nachnamen in der Realität vorkommen, lässt sich nicht vermeiden. Die muss man dann trotzdem irgendwie auseinander halten können.

Ich persönlich bin mit einem führenden Unterstrich sparsam und setze den meisten nur wenn es wirklich verlockend erscheint direkt etwas mit einem Attribut zu machen *und* dabei leicht etwas kaputt gehen kann. Ansonsten stört mich das in der Regel nicht das Attribute öffentlich sind. Doppelte führende Unterstriche habe ich glaube ich bei normalen Klassen noch *nie* gebraucht. Die sind zur Vermeidung von Namenskollisionen in tiefen Vererbungshierarchien oder bei Mehrfachvererbung. Beides kommt in Python nur sehr selten vor und ist meistens ein Zeichen das man zu viel Komplexität per Vererbung gebastelt hat, die man vielleicht besser anders auflösen sollte.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
Antworten