[gelöst] Klassen, die miteinander interagieren

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.
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

Hallo,

ich wollte mal lernen richtig objektorientiert zu programmieren. Bis jetzt hatte ich immer nur eine Klasse und habe darin dann prozedural programmiert. Leider haben auch alle Beispielcodes, die ich so kenne nur eine Klasse oder sind vieeeeel zu schwer zu verstehen.

Kennt jemand ein leichtes Beispiel, wo mehrere Klassen miteinander agieren und vielleicht ein Objekt mehrere andere Objekte aufnimmt und die vielleicht auch speichert?

Mir fällt da z.B. eine Schule ein:
-3 Klassen (Schüler, Klasse, Schule)
-Schüler mit Name, Alter, Aussehen
-Klasse, die die Schüler beinhaltet und auch eigene Besonderheiten hat (Jahrgang etc.)
-Schule, die die Klassen enthält und auch gespeichert werden kann

Falls dies gespeichert wurde - wie greife ich dann wieder auf einen Schüler zu?
SchuleXY.KlasseXY.Franz.name?

Vielleicht kennt ja jemand etwas, wo man das mal anhand von einfachen Codebeispielen lernen kann.

So long
Carsten
Zuletzt geändert von Zando am Donnerstag 28. Februar 2008, 10:43, insgesamt 2-mal geändert.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dein Ansatz ist doch schon mal nicht schlecht! Allerdings solltest Du Dir auch Funktionalität überlegen die Du in eine Klasse packst. Im Moment nutzt Du die ja stumpf als Datenobjekte (was natürlich an sich nicht verkehrt ist!), aber so lernt man den eigentlich Vorteil bzw. die Besonderheit von Klassen nicht wirklich.

Hast Du das Tutorial mal durchgearbeitet? Dort wird ja auch auf Klassen eingegangen!

Die einfachste Funktionalität könnte es sein, dass sich jede Klasse selber in Textform ausgibt. So braucht die Klasse "Schule" nicht jede einzelne Klasse "Klasse" aufrufen, sondern muss nur über die "Klassen" iterieren und deren "print"-Methode aufrufen.

Also, am besten mal ganz einfach anfangen!
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

Hyperion hat geschrieben:Allerdings solltest Du Dir auch Funktionalität überlegen die Du in eine Klasse packst. Im Moment nutzt Du die ja stumpf als Datenobjekte (was natürlich an sich nicht verkehrt ist!), aber so lernt man den eigentlich Vorteil bzw. die Besonderheit von Klassen nicht wirklich.
Naja, man kann ja noch Funktionen einbringen. Schüler altern lassen, Auslandsjahr machen lassen oder so... Schule abbrennen (nein, Scherz *g*).
Hast Du das Tutorial mal durchgearbeitet? Dort wird ja auch auf Klassen eingegangen!
Welches meinst du jetzt direkt? Die zwei, die ich schön finde sind (an der Stelle Klassen):
http://www.ibiblio.org/swaroopch/byteof ... asses.html
und
http://docs.python.org/tut/node11.html

Hier ist aber, wie ich schon anmerkte, immer nur eine Klasse dargestellt und nicht wie diese mit anderen interagiert :(
Die einfachste Funktionalität könnte es sein, dass sich jede Klasse selber in Textform ausgibt. So braucht die Klasse "Schule" nicht jede einzelne Klasse "Klasse" aufrufen, sondern muss nur über die "Klassen" iterieren und deren "print"-Methode aufrufen.
Und wie würde sowas gehen? Man braucht doch immer den Instanzname, um etwas spezielles aufzrufen? Genau diese meinte ich, hier hören die Tutorials auf... Vielleicht denke ich aber auch nur zu kompliziert?

Danke aber für deine Antwort, das mit den Funktionen hat schon zum Nachdenken angeregt

Aber ich hätte halt gern mal ein komplettes Beispiel (mit Klassendefinition, Instanzierung und Benutzen der Instanzen mit Bezugnahme auf andere Instanzen). Es muss ja nicht mein Schulbeispiel sein, das sollte auch eher nur verdeutlichen, was ich meine. Gibt es soetwas denn nicht?

Grüße
Carsten
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

http://paste.pocoo.org/show/30255/ :)

Edit: Das Programm enthaelt einen kleinen Fehler. Der ist natuerlich extra zu Uebungszwecken eingebaut. :wink:
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ok, dann mal auf die Schnelle und ungetestet:

Code: Alles auswählen

class Student(object):
    def __init__(self, name):
        self.name = name

    def foo(self):
        print "Ich bin eine Instanz von Student und mein Name ist", self.name

class Grade(object):
    def __init__(self, name):
        self.name = name
        self.students = []

    def foo(self):
        print "Ich bin eine Instanz von Grade und mein Name ist", self.name

    # Genau das scheint Dir noch unklar zu sein :-)
    def printStudents(self):
        for i in self.students:
            i.foo()

def main():
    c = Class("10a")
    c.foo()
    students = [Student("Peter Müller"), Student("Max Mustermann")]
    c.students = students
    c.printStudents()
Ok, war nicht schnell genug! Obiges Bsp ist natürlich viel schöner :-)
BlackJack

Kleines Beispiel mit Würfeln, das als Grundlage für Yatzee/Kniffel dienen könnte:
http://paste.pocoo.org/show/30260/
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

hui, gibt es hier viele Antworten :)

@Rebecca: danke, sieht sehr übersichtlich aus, aber ich habe auf die Schnelle keinen Fehler finden können. Vielleicht bekomme ich eine Fehlermeldung, wenn ich zuhause teste (bin grad auf Arbeit) *g*

@Hyperion: Ich denke mal es muss in der main-Funktion c = Grade("10a") heißen. Aber ansonsten hast du genau den Punkt getroffen, der mir unklar ist ;) Eigentlich weiß man ja erst im Programm, wie die jeweilige Instanz heißt, aber wenn man den Namen bei der Initialisierung gleich mit übergibt und einen "internen" Namen gibt, kann man natürlich mit schon "bekannten" Variablen arbeiten, guter Gedanke...

@BlackJack: Ein Würfelbeispiel passt zu deinem Namen :D
Aber sowas:

Code: Alles auswählen

self.dices = [Dice(sides) for dummy in xrange(number)]
wollte ich eigentlich IN der Klasse vermeiden. Habe irgendwann mal gelesen, dass es besser sei immer mit Instanzen zu arbeiten anstatt mit den Objekten direkt? Aber auch ein nettes Beispiel trotzdem...

Wäre es auch guter Programmierstil Instanzen von Klassen in anderen Klassen zu verwenden?

Warum bedarf es für sowas erst einen Forenbeitrag? Können die Tutorials das nicht enthalten? (rhetorische Fragen *g*)

So long und nochmals Danke für eure Hilfe
Carsten

P.S.: Ich teste mal heute oder morgen abend die Beispiele und setze den Thread auf gelöst, wenn ich keine Fragen mehr habe :)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Zando hat geschrieben: @Hyperion: Ich denke mal es muss in der main-Funktion c = Grade("10a") heißen. Aber ansonsten hast du genau den Punkt getroffen, der mir unklar ist ;)
Äh ... ja, natürlich ;-) Das deutsche Wort Klasse ist in dieser Thematik leider doppelt belegt :-D
Eigentlich weiß man ja erst im Programm, wie die jeweilige Instanz heißt, aber wenn man den Namen bei der Initialisierung gleich mit übergibt und einen "internen" Namen gibt, kann man natürlich mit schon "bekannten" Variablen arbeiten, guter Gedanke...
Das habe ich nun wieder nicht verstanden?
@BlackJack: Ein Würfelbeispiel passt zu deinem Namen :D
Aber sowas:

Code: Alles auswählen

self.dices = [Dice(sides) for dummy in xrange(number)]
wollte ich eigentlich IN der Klasse vermeiden. Habe irgendwann mal gelesen, dass es besser sei immer mit Instanzen zu arbeiten anstatt mit den Objekten direkt? Aber auch ein nettes Beispiel trotzdem...
Also für mich ist Objekt = Instanz! Liege ich da falsch oder siehst Du das "falsch"? Erbitte da Aufklärung!
Wäre es auch guter Programmierstil Instanzen von Klassen in anderen Klassen zu verwenden?
Also wenn wir bei der Terminologie dieselbe Sprache sprechen (s.o.), dann muss man das sogar tun, wenn man denn mit verschachtelten Klassen arbeiten will! In meinem Beispiel hält das Attribut students eben eine Liste von Instanzen der Klasse Student. Prinzipiell wird eine Vernestelung immer auf diese Weise erreicht (neben Listen eben auch durch andere Container).
Warum bedarf es für sowas erst einen Forenbeitrag? Können die Tutorials das nicht enthalten? (rhetorische Fragen *g*)
Tja, schreib doch einfach selber eines von einem Anfänger für Anfänger! Ich bin nicht mit Python groß geworden, daher war mir von vornherein einiges "klar", was bei anderen Vorkenntnissen evtl. halt zu Problemen geführt haben könnte. Insofern ist es natürlich auch schwer ein Tutorial so zu schreiben, dass es jeder versteht - wenn das so leicht ginge, wären wir alle Theoretische Physiker :-D
BlackJack

@Zando: Man könnte die einzelnen Würfel in einem `Dices`-Objekt auch von aussen "zuführen", oder der `Dices.__init__()` ein Argument hinzufügen, so dass die Würfel zwar in der Methode erzeugt werden, aber der Benutzer der Klasse selbst bestimmen kann, wie so ein Würfel aussieht, wenn er denn möchte:

Code: Alles auswählen

    def __init__(self, number=5, sides=6, dice_factory=Dice):
        self.dices = [dice_factory(sides) for dummy in xrange(number)]
Das kommt aber letztendlich immer auf den Verwendungszweck an. Wenn der Benutzer der Würfel eh nur mit `Dices`-Objekten konfrontiert werden soll, dann ist `Dice` ein Implementierungsdetail, was er nicht kennen muss und alles andere zu komplex.

Man sollte auf jeden Fall vermeiden Quelltext von vornherein zu flexibel zu schreiben. Er sollte natürlich schon flexibel sein, aber wenn man zu viel abstrahiert, hat man hinterher viel komplexeren Code, den man gar nicht benötigt.

Die Änderung da oben kann man zum Beispiel immer noch nachträglich machen, ohne das sich die API für bestehenden Quelltext ändert.

Man sollte keinen Code schreiben, den man so nicht benötigt. Darum der Rat von Hyperion gleich in der ersten Antwort, dass Du Dir Gedanken über die Funktionalität machen sollst. Alles was für die geplante Funktionalität nicht benötigt wird, ist toter Ballast, der den Quelltext länger macht und Fehler enthalten kann.

"Test driven development" (TDD) kann da hilfreich sein. Man macht sich Gedanken über die Funktionalität, also was will ich mit den Objekten machen. Dann schreibt man einen Test. Dann den Code, damit dieser Test korrekt läuft. Dann den nächsten Test und danach den Code dazu, und so weiter.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben: "Test driven development" (TDD) kann da hilfreich sein. Man macht sich Gedanken über die Funktionalität, also was will ich mit den Objekten machen. Dann schreibt man einen Test. Dann den Code, damit dieser Test korrekt läuft. Dann den nächsten Test und danach den Code dazu, und so weiter.
Interessanter Ansatz - kannte ich noch nicht. Muss mich da mal schlau lesen!
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

Hyperion hat geschrieben:
Zando hat geschrieben: Eigentlich weiß man ja erst im Programm, wie die jeweilige Instanz heißt, aber wenn man den Namen bei der Initialisierung gleich mit übergibt und einen "internen" Namen gibt, kann man natürlich mit schon "bekannten" Variablen arbeiten, guter Gedanke...
Das habe ich nun wieder nicht verstanden?
egal, ich schon. Da habe ich schon weitergedacht, wie es ist, wenn man mal die Namen der Instanzen bei der Programmierung noch nicht kennen sollte ;)
@BlackJack: Ein Würfelbeispiel passt zu deinem Namen :D
Aber sowas:

Code: Alles auswählen

self.dices = [Dice(sides) for dummy in xrange(number)]
wollte ich eigentlich IN der Klasse vermeiden. Habe irgendwann mal gelesen, dass es besser sei immer mit Instanzen zu arbeiten anstatt mit den Objekten direkt? Aber auch ein nettes Beispiel trotzdem...

Also für mich ist Objekt = Instanz! Liege ich da falsch oder siehst Du das "falsch"? Erbitte da Aufklärung!
Kommando zurück, es wird ja hier auch eine Liste generiert. Und die Worte Objekt und Klasse hab ich auch verwechselt :oops:
Also wenn wir bei der Terminologie dieselbe Sprache sprechen (s.o.), dann muss man das sogar tun, wenn man denn mit verschachtelten Klassen arbeiten will! In meinem Beispiel hält das Attribut students eben eine Liste von Instanzen der Klasse Student.
Ok, danke, das wollte ich nur wissen...
Tja, schreib doch einfach selber eines von einem Anfänger für Anfänger! Ich bin nicht mit Python groß geworden, daher war mir von vornherein einiges "klar", was bei anderen Vorkenntnissen evtl. halt zu Problemen geführt haben könnte.
Und ich habe "immer" (immer mal) nur prozedural programmiert und mit Basic auf dem C64 angefangen :D
Daher ist es schwierig sich da reinzudenken. Sieht man ja schon bei der Benamsung (Instanz, Klasse) und eben dem Zusammenspiel von Klassen, was ja hier schön rübergekommen ist...

Und zum Selberschreiben: ich habe ja schon ein paar Tutorials gelesen und die Grundlagen kommen gut rüber, aber Klassen werden halt immer sehr kurz behandelt (eh ich mal "self" verstanden habe, gingen auch viele Sonnen unter ;) )

So long
Carsten
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

BlackJack hat geschrieben: Das kommt aber letztendlich immer auf den Verwendungszweck an. Wenn der Benutzer der Würfel eh nur mit `Dices`-Objekten konfrontiert werden soll, dann ist `Dice` ein Implementierungsdetail, was er nicht kennen muss und alles andere zu komplex.

Man sollte auf jeden Fall vermeiden Quelltext von vornherein zu flexibel zu schreiben. Er sollte natürlich schon flexibel sein, aber wenn man zu viel abstrahiert, hat man hinterher viel komplexeren Code, den man gar nicht benötigt.
Genau das meinte ich mit nicht IN der Klasse direkt, da ich immer sehr darauf achte, dass etwas flexibel ist. Vielleicht sollte ich mich davon etwas lösen. Und das es Instanzen sind, habe ich ja im vorigen Post schon zugegeben ;)

So long
Carsten
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Hyperion hat geschrieben:
BlackJack hat geschrieben: "Test driven development" (TDD) kann da hilfreich sein. Man macht sich Gedanken über die Funktionalität, also was will ich mit den Objekten machen. Dann schreibt man einen Test. Dann den Code, damit dieser Test korrekt läuft. Dann den nächsten Test und danach den Code dazu, und so weiter.
Interessanter Ansatz - kannte ich noch nicht. Muss mich da mal schlau lesen!
Z.B. hier: diveintopython
Habe jetzt gerade Testgetriebene Entwicklung mit JUnit & FIT gelesen. Ist zwar für Java, von dem ich eigentlich keine Ahnung habe, kann man aber auch gut für Python verwenden. Für die Software-Entwicklung im professionellen Bereich finde ich den Ansatz gut, für den Home-User eher übertrieben und auch kaum in der Konsequenz umsetzbar.
MfG
HWK
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

Rebecca hat geschrieben:http://paste.pocoo.org/show/30255/ :)

Edit: Das Programm enthaelt einen kleinen Fehler. Der ist natuerlich extra zu Uebungszwecken eingebaut. :wink:
Also ich konnte gestern abend keinen Fehler entdecken. Lief ohne zu meckern das Programm...

So long
Carsten

edit: Noch eine Frage so allgemein: sollte man das "object" bei einer Klassendefinition mit angeben?

Also "Klasse(object):" anstatt "Klasse:"?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Zando hat geschrieben:
Rebecca hat geschrieben: edit: Noch eine Frage so allgemein: sollte man das "object" bei einer Klassendefinition mit angeben?

Also "Klasse(object):" anstatt "Klasse:"?
Kommt drauf an: Stichwort new-style-classes!
[wiki]New-Style Klassen[/wiki]?highlight=%28klasse%29
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

Hyperion hat geschrieben:
Zando hat geschrieben: Wäre es auch guter Programmierstil Instanzen von Klassen in anderen Klassen zu verwenden?
Also wenn wir bei der Terminologie dieselbe Sprache sprechen (s.o.), dann muss man das sogar tun, wenn man denn mit verschachtelten Klassen arbeiten will! In meinem Beispiel hält das Attribut students eben eine Liste von Instanzen der Klasse Student. Prinzipiell wird eine Vernestelung immer auf diese Weise erreicht (neben Listen eben auch durch andere Container).
Die Antwort war mir gestern klarer, da ich meine Frage wieder unpräzise gestellt habe und die Antwort ja gepasst hat :)

Ich meinte eher: Wäre es guter Programmierstil die Instanzen auch in den anderen Klassen zu erzeugen? Ihr (Rebecca und du) erzeugt die Instanzen ja außerhalb der Klassen (anderen Instanzen?), während BlackJack sie innerhalb erzeugt.

Falls ich wieder sprachliche Probleme habe, hier ein Beispiel:

"ihr" macht es so:

Code: Alles auswählen

class Erste:
    pass
class Zweite:
    def __init__(self, wasvomersten):
        blablablub...

ausserhalb = Erste()
zweite = Zweite(ausserhalb)
und BlackJack so:

Code: Alles auswählen

class Erste:
    pass
class Zweite:
    def __init__(self):
        self.innerhalb = Erste()
Ok, ist mir während des Schreibens klarer geworden :D
BlackJacks Lösung ist eher dafür falls alle Zweite-Objekte(Instanzen) DASGLEICHE Erste-Objekt enthalten sollen und "eure" eher falls es verschiedene Erste-Objekte gibt, die in den verschiedenen Zweite-Objekten verwendet werden sollen?

So long
Carsten

edit: vor "innerhalb" im Quellcode noch ein "self" gesetzt...
Zuletzt geändert von Zando am Donnerstag 28. Februar 2008, 11:16, insgesamt 1-mal geändert.
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

Hyperion hat geschrieben:
Zando hat geschrieben:
Kommt drauf an: Stichwort new-style-classes!
[wiki]New-Style Klassen[/wiki]?highlight=%28klasse%29
Kommt drauf an :D Eine typische Studentenantwort würde ich mal sagen. Aber obwohl ich in der Beschreibung nur Bahnhof verstehe, steht da was von alten Klassen fehleranfällig und da werde ich wohl die neue Variante bevorzugen...

So long
Carsten
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Zando hat geschrieben:Ok, ist mir während des Schreibens klarer geworden :D
BlackJacks Lösung ist eher dafür falls alle Zweite-Objekte(Instanzen) DASGLEICHE Erste-Objekt enthalten sollen und "eure" eher falls es verschiedene Erste-Objekte gibt, die in den verschiedenen Zweite-Objekten verwendet werden sollen?
Nein, die __init__-Methode wird ja bei jedem Mal aufgerufen, wenn eine neue Instanz erzeugt wird. Also wird in BlackJacks fall bei jedem Erzeugen einer Zweite-Instanz auch eine neue Erste-Instanz erzeugt.

Der Unterschiede ist einfach der, dass bei BlackJacks halt "irgendeine" Erste-Instanz erzeugt wird, der Benutzer der Zweite-Klasse hat darauf keinen Einfluss. In meinen Fall kann der Benutzer der Zweite-Klasse genau entscheiden, welche Erzte-Instanz in der Zweite-Instanz vorhanden sein soll. Das macht in der Schulklassen-Klasse ja auch sinn: Es sind ganz bestimmte Schueler in der Klasse (Max Mustermann, Helga Hampel,...), nicht irgendwelche Standard-Schueler.
Offizielles Python-Tutorial (Deutsche Version)

Urheberrecht, Datenschutz, Informationsfreiheit: Piratenpartei
Zando
User
Beiträge: 37
Registriert: Sonntag 9. Juli 2006, 17:18

@Rebecca: ich könnte mich jetzt rausreden und sagen, das mit dasgleiche ja unterschiedliche gemeint sind und nicht dasselbe. Aber da hab ich in dem Moment gar nicht so dran gedacht. Im Endeffekt ist es aber so wie ich es mir dachte.

Mit dem Einfluss drauf haben, ist es vielleicht noch etwas besser beschrieben, danke *g*

So long
Carsten
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Naja, im Endeffekt ist es gar nicht so verschieden, wenn man an ein komplexes Programm denkt. Dort wirst Du sicherlich Klassen haben, innerhalb deren andere Instanzen erzeugt werden. Ob das nun aus einer Funktion heraus geschieht oder eben aus einer Klasse bzw einer ihrer Methoden macht imho keinen großen Unterschied :)
Antworten