Seite 1 von 1
Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 09:58
von mcdwerner
Hallo!
Über die Verwendung von Python-Klassen hab ich nun schon jede Menge Tutorials und Snippets gelesen aber die eigene Umsetzung gelingt mir nicht so recht.
Nun steht der Urlaub an und wenn man sich in der Familie nicht einigen kann muss der Zufall aushelfen
Dazu hab ich mir folgendes Skript überlegt und nun denke ich mir, dass Klassen ganz nützlich wären, wenn ich das Skript noch um weitere "Attraktionen" und "Events" erweitern möchte.
Code: Alles auswählen
import random
def einzigartigeAttraktion(n):
#übernimmt 0, 1 oder 2
Auswahl = n
if Auswahl == 2:
Auswahl = random.randint(0,1)
if Auswahl:
return 'Yippie, wir besuchen die einzigartige Attraktion.'
else:
return 'einzigartige Attraktion: Nö!'
def Strand1(von, bis):
#übernimmt 2 Argumente: Zufallsauswahl von bis...
von = von
bis = bis
if bis == 0:
strand = 0
else:
strand = random.randint(0,1)
if strand:
strandreturn = 'Wir gehen ' + str(random.randint(von, bis)) + ' mal an Strand 1.'
else:
strandreturn = 'Strand 1: Nö!'
return strandreturn
def Segeln(von, bis):
von = von
bis = bis
if bis == 0:
segeln = 0
else:
segeln = random.randint(0,1)
if segeln:
return random.randint(von, bis)
else:
return 0
def Strand2(von, bis):
#nur hier kann man segeln...
von = von
bis = bis
if von == 'Segeln':
von = Segeln(1,5)
bis = von + bis
strand = 2
else:
if bis == 0:
strand = 0
else: strand = random.randint(0,1)
if strand == 1:
strandreturn = 'Wir gehen ' + str(random.randint(von, bis)) + ' mal an Strand 2, ohne Segeln.'
elif strand == 0:
strandreturn = 'Strand 2: Nö!'
elif strand == 2:
strandreturn = 'Wir gehen ' + str(random.randint(von, bis)) + ' mal an Strand 2, davon' + str(von) + ' mal Segeln.'
return strandreturn
Leider finde ich keinen rechten Einstieg Richtung Klassenverwendung, hat einer von Euch einen Denkanstoß für mich?
Vielen Dank schonmal und beste Grüße,
Werner
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 10:21
von BlackJack
@mcdwerner: Also ich verstehe den Quelltext mit den Funktionen schon nicht wirklich, darum ist es schwierig den mit Klassen zu modellieren.
Ein Grund warum der Quelltext schwer zu verstehe ist, sind die vielen magischen Zahlen, die da herum schwirren. Zum Beispiel bei der `einzigartigeAttraktion()`-Funktion muss man die Funktion selbst lesen um zu wissen was das Argument `n` bedeutet.
Ähnliches gilt für `von` und `bis` bei den anderen Funktionen. Da war meine erste Vermutung beim Lesen der Signaturen es könnten Zeiten sein. Da war ich jetzt zu faul den Quelltext zu lesen und zu raten was sie wirklich bedeuten.
Warum bindest Du als aller erstes in den Funktionen eigentlich die Argumente noch einmal an die gleichen Namen? Das hat keinen Effekt.
Funktionsnamen tun etwas, deshalb sollten sie nicht Namen von Dingen sondern von Tätigkeiten haben. Und diese Namen sollten beschreiben, was die Funktionen tun.
Mir scheint die Funktionsnamen kodieren bei Dir eigentlich Daten. Zum Beispiel Ausflugsziele und Tätigkeiten, die man dort ausführen kann. Vielleicht solltest Du das eher in eine Datenstruktur stecken, die zum Beispiel einen Baum mit Entscheidung@mcdwerner: Also ich verstehe den Quelltext mit den Funktionen schon nicht wirklich, darum ist es schwierig den mit Klassen zu modellieren.
Ein Grund warum der Quelltext schwer zu verstehe ist, sind die vielen magischen Zahlen, die da herum schwirren. Zum Beispiel bei der `einzigartigeAttraktion()`-Funktion muss man die Funktion selbst lesen um zu wissen was das Argument `n` bedeutet.
Ähnliches gilt für `von` und `bis` bei den anderen Funktionen. Da war meine erste Vermutung beim Lesen der Signaturen es könnten Zeiten sein. Da war ich jetzt zu faul den Quelltext zu lesen und zu raten was sie wirklich bedeuten.
Warum bindest Du als aller erstes in den Funktionen eigentlich die Argumente noch einmal an die gleichen Namen? Das hat keinen Effekt.
Funktionsnamen tun etwas, deshalb sollten sie nicht Namen von Dingen sondern von Tätigkeiten haben. Und diese Namen sollten beschreiben, was die Funktionen tun.
Mir scheint die Funktionsnamen kodieren bei Dir eigentlich Daten. Zum Beispiel Ausflugsziele und Tätigkeiten, die man dort ausführen kann. Vielleicht solltest Du das eher in eine Datenstruktur stecken, die zum Beispiel einen Baum mit Entscheidungsmöglichkeiten modelliert. *Das* könnte man dann zum Beispiel auch mit Klassen für die einzelnen Knoten in dem Baum machen. Dein Beispiel hätte dann drei Knoten in der ersten Ebene und beim zweiten Strand noch zwei weitere Auswahlmöglichkeiten.
smöglichkeiten modelliert. Das könnte man dann zum Beispiel auch mit Klassen für die einzelnen Knoten in dem Baum machen. Dein Beispiel hätte dann drei Knoten in der ersten Ebene und beim zweiten Strand noch zwei weitere Auswahlmöglichkeiten.
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 10:47
von mcdwerner
Hallo Blackjack!
Die Funktionen sollen nach Zufall entscheiden, ob etwas im Urlaub gemacht wird und wenn ja, wie oft.
Die Zahlen, die den Funktionen übergeben werden sollen die Entscheidungen eingrenzen: z.B. Anzahl von - bis
Das Skript soll mehr eine Programmierübung sein als eine ernsthafte, schnelle Umsetzung.
Das Ergebnis soll eine Liste mit Vorschlägen sein, wie man den Urlaub verbringen könnte.
Dinge wie: wie teile ich die vorhandene Urlaubs-Zeit auf die Aktionen auf, wie gebe ich die Liste aus etc sind in diesem Skript momentan nicht enthalten, sollen aber noch implementiert werden.
Dein Hinweis, dass meine Funktionen eigentlich Daten kodieren schwirrt mir auch schon die ganze Zeit im Kopf rum! Daher die Idee Klassen daraus zu machen. ( -> grundsätzlich richtiger Denkansatz???)
Mit Programmierung und Python beschäftige ich mich in meiner Freizeit seit ca 4 Wochen, darum sieht das ganze vielleicht nach (bayrisch) "ebbs und nix" aus (hochdeutsch evtl. "weder Fisch noch Fleisch"?).
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 11:34
von Hyperion
mcdwerner hat geschrieben:
Das Ergebnis soll eine Liste mit Vorschlägen sein, wie man den Urlaub verbringen könnte.
Dinge wie: wie teile ich die vorhandene Urlaubs-Zeit auf die Aktionen auf, wie gebe ich die Liste aus etc sind in diesem Skript momentan nicht enthalten, sollen aber noch implementiert werden.
Genau hier sehe ich aber den Denkfehler. Du musst Dir doch eigentlich erst überlegen, aus welchen Daten Du welche Daten erzeugst! Wer bestimmt denn, wie das Minimum und das Maximum für einen Strandbesuch aussehen? Was sind eigentlich Strand1 und Strand2? BlackJack hatte ja einige Vermutungen angestellt; in diese Richtung musst Du jetzt mal denken und versuchen uns den Plan / die Idee präzise zu schildern.
Vorher kann man auch wenig zur Benutzung von Klassen sagen.
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 12:07
von mcdwerner
Diese Funktion hier kriegt entweder 0,1 oder 2 übergeben:
Bei 0 wird die einzigartige Attraktion auf keinen Fall besucht, bei 1 auf jeden Fall und bei 2 lassen wir den Zufall entscheiden
Code: Alles auswählen
def einzigartigeAttraktion(n):
#übernimmt 0, 1 oder 2
Auswahl = n
if Auswahl == 2:
Auswahl = random.randint(0,1)
if Auswahl:
return 'Yippie, wir besuchen die einzigartige Attraktion.'
else:
return 'einzigartige Attraktion: Nö!'
Ähnlich hier:
Code: Alles auswählen
def Strand1(von, bis):
#übernimmt 2 Argumente: Zufallsauswahl von bis...
von = von
bis = bis
if bis == 0:
strand = 0
else:
strand = random.randint(0,1)
if strand:
strandreturn = 'Wir gehen ' + str(random.randint(von, bis)) + ' mal an Strand 1.'
else:
strandreturn = 'Strand 1: Nö!'
return strandreturn
wenn das zweite Argument "bis" == 0 haben wir uns entschieden diesen Strand nicht zu besuchen ansonsten soll der Zufall entscheiden, wie oft wir hingehen, eingegrenzt zwischen von - bis
Wenn ich das ganze Skript folgendermaßen laufen lasse:
print(einzigartigeAttraktion(2), '\n', Strand1(5, 10), '\n', Strand2('Segeln', 7))
erhalte ich folgendes zufällige Ergebnis:
Yippie, wir besuchen die einzigartige Attraktion.
Strand 1: Nö!
Wir gehen 2 mal an Strand 2, davon 0 mal Segeln.
Und schon sind alle Diskussionen beendet (zumindest in der Familie
Ich könnte natürlich so ähnliche Funktionen für jede "Attraktion" schreiben (Museum 1-4, Restaurant 1-8 etc....) aber genau das sollten Klassen nach meinem Verständnis vereinfachen:
Ich schreibe je eine Klasse Strände, Museen, Restaurants, Attraktionen etc erstelle zu jedem Museum, Rastaurant eine entsprechende Instanz der Klasse und schon kann ich den ganzen Urlaub verplanen und wenn's nicht schön ist, dann ist der Zufall schuld...
Ich könnte natürlich auch eine Liste von Zeitpunkten (1. Tag Mittag, 1. Tag Nachmittag etc....) erzeugen und jedem Listenpunkt eine bestimmte Aktion zuteilen aber ich möchte wetterunabhängig sein und deshalb reicht mir eine Liste in der z.B. steht "Wir gehen 2 mal an Strand 2, davon 0 mal Segeln."
Hoffe es ist jetzt verständlicher?
Wie gesagt, es geht mir weniger um die konkrete Urlaubs-Umsetzung, mehr um die Programmierübung.
Edith sagt:
Wenn die Anzahl der Aktionen die das Programm ausspukt (z.B: 48) nicht zur vorhandenen Zeit passt (z.b: 35) dann wird einfach nach Verhältnis umgerechnet (grob gesagt: jedes einzelne Ergebnis mal 35 geteilt durch 48)
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 13:42
von Hyperion
Die Frage ist doch, inwiefern sich "Aktionen" im Urlaub von einander unterscheiden bei Deiner "Planung". Das ist die Kunst der Abstraktion. Natürlich kann man loslegen und alles in Klassen verpacken - aber was gewinnst Du dadurch? Du musst zuerst ein Verständnis dafür bekommen, welche Daten und welche Operationen für die Modellierung Deines Problems benötigt werden.
Löse Dich doch mal vom Code und überlege Dir erst einmal genau, was Du für verschiedene "Aktionen" im Urlaub hast und was der Computer per Zufall jeweils bei diesen "berechnen" soll. Dann kannst Du anfangen zu überprüfen, ob und inwiefern sich diese Aktionen unterscheiden. Evtl. gelangt man dann zu einem Punkt, wo sich Klassen und spezialisierte Unterklassen prima für die Modellierung nutzen lassen. Im Moment zweifel ich noch daran bei diesem Problem.
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 14:33
von problembär
Geh' doch einfach mal an den Strand.

Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 14:37
von BlackJack
@problembär: Mit oder ohne segeln?

Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 14:50
von mcdwerner
OK, let's try! Wir brauchen:
Klasse "einzigartige Attraktion, Sehenswürdigkeit", Instanzen z.B.: Colloseum, ein bestimmtes Museum etc...:
muss nur max 1x besucht werden, jede Instanz sollte folgende Wahlmöglichkeiten haben: auf jeden Fall besuchen, auf keinen Fall besuchen, Zufall entscheiden lassen
evtl eine "Schnittstelle" zu anderen Instanzen: wenn A schon besucht wird soll B auf keinen/jeden Fall besucht werden
Oberklasse "Attraktionen die mehrfach besucht werden sollen"
Mehrfachbesuch-Unterklasse "Restaurants":
jede Instanz sollte folgende Wahlmöglichkeiten haben: auf jeden Fall besuchen, auf keinen Fall besuchen, Zufall entscheiden lassen ob besucht wird. Wenn sie besucht werden soll: per Zufall entscheiden lassen, wie oft. Wobei ein gewisser Rahmen vorgegeben wird (z.B. mindestens 1x und höchstens 6x besuchen)
Am Ende kann die Zahl der Restaurantbesuche mit dem Urlaubsplan abgestimmt werden (nach dem Verhältnisprinzip)
evtl eine "Schnittstelle" zu anderen Instanzen: wenn A schon besucht wird soll B auf keinen/jeden Fall besucht werden
Mehrfachbesuch-Unterklasse "Freizeit", Instanzen z.B. versch Strände, Berge etc... :
jede Instanz sollte folgende Wahlmöglichkeiten haben: auf jeden Fall besuchen, auf keinen Fall besuchen, Zufall entscheiden lassen ob besucht wird. Wenn sie besucht werden soll: per Zufall entscheiden lassen, wie oft. Wobei ein gewisser Rahmen vorgegeben wird (z.B. mindestens 1x und höchstens 6x besuchen)
Am Ende kann die Zahl der Strandbesuche mit dem Urlaubsplan abgestimmt werden (nach dem Verhältnisprinzip)
evtl eine "Schnittstelle" zu anderen Instanzen: wenn A schon besucht wird soll B auf keinen/jeden Fall besucht werden
Klasse "kann nur besucht werden wenn auch gleichzeitig was anderes besucht wird"
im Beispiel "Segeln kann nur besucht werden wenn Strand2 besucht wird"
evtl über die "Schnittstelle" handeln???
auch hier wieder die Wahlmöglichkeiten: auf jeden Fall besuchen (wenn möglich), auf keinen Fall besuchen, Zufall entscheiden lassen ob besucht wird. Wenn sie besucht werden soll: per Zufall entscheiden lassen, wie oft. Wobei ein gewisser Rahmen vorgegeben wird (z.B. mindestens 1x und höchstens so oft besuchen, wie die Instanz von der der Besuch abhängt)
Als Eingabe:
die verschiedenen Attraktionen mit den zugehörigen Bedingungen und evtl Abhängigkeiten
Ausgabe:
die verschiedenen Attraktionen und die (per Zufall errechneten) Besuchshäufigkeiten evtl mit den Abhängigkeiten
mit einfachen Mitteln möglich oder eher nicht?
@ Problembär:
mir ist klar, dass das ganze ein wenig realitätfremd ist! Hab gehofft das macht's einfacher. Ist offensichtlich nicht so...
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 15:51
von Hyperion
Du bist immer noch einen Schritt zu schnell!
Alleine wenn Du Dir Deine beiden Modelle "Restaurants" und "Freizeit" anguckst, unterscheiden die sich nicht die Bohne - außer von der Begrifflichkeit! Und Dein Modell für die "einzigartigen" Dinge ist streng genommen eher ein Spezialfall der beiden anderen und benötigt also keinen speziellen Typen.
Du musst Dich hier imho noch mal von Klassen lösen und auf einem höherem Niveau abstrahieren.
Gerade solche Dinge wie "wenn eine Sache besucht wird, darf eine bestimmte andere nicht mehr besucht werden" ist alles andere als trivial. Einfacher wäre es, wenn Du solche Aktionen von vorherein in eine "one-of"-Relation packst. Du siehst, vieles ist einfach eine Frage der Modellierung.
Bevor Du Dich also um "Klassen"-Modelle kümmerst, musst Du Dir erst einmal klar werden, wie Du die Daten repräsentierst. Benötigst Du eine spezielle Logik? Kann man das über Graphen lösen? Wie definiert man die Reihenfolge? Gibt es andere Prinzipien, auf die man das runterbrechen kann?
Wenn man mal "Abhängigkeiten" außen vor lässt, würde ich erst einmal ganz banal mit Tupeln arbeiten:
Code: Alles auswählen
activities = (
("Strand", 3, 6),
("Colosseum", 1, 1),
("Freizeitpark", 0, 1),
("Sixtinische Kapelle", 0, 0)
)
def create_schedule(activities):
result = []
for name, min_, max_ in activities:
result.extend([name for _ in xrange(0, randint(min_, max_))])
return result
Wie Du siehst ist das ein ganz einfaches Modell - kommt aber ohne Klassen aus. Immerhin kann ich eine Aktivität immer einplanen, gar nicht oder eben mit beliebiger unterer und oberer Schranke. (Wobei ich gar nicht ziemlich sinnlos finde - da muss ich diesen Freizeitaspekt auch erst gar nicht angeben

)
Will man noch Aktivitäten unterbringen, so dass man die nur dann erledigen kann, wenn man schon etwas anderes gemacht hat, so muss man sich wohl ein Graphenmodell ausdenken. Am einfachsten wäre es, wenn Dinge nur von einer Sache abhängen, dann reicht ein Baum. Können Sachen von mehreren Dingen abhängen, wird es komplexer, da man den Graphen anders traversieren muss.
So langsam denke ich, dass das ganze ein wenig an einen Schaltkreis mit den Standard-Logik-Elementen erinnert. Evtl. ist das ein Ansatzpunkt, komplexere Dinge zu modellieren.
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 20:05
von mcdwerner
Oh Mann! Danke Hyperion!!!!
Da gibt's noch viel zu lernen für einen Einsteiger.
Und ich dachte noch "Das ist sicher ein gutes Beispiel um endlich mal die 'Klassenlogik' zu kapieren"...
Habt ihr evtl ein paar Beispiele abseits der Schiene: Mensch - Schulmitglied - Lehrer/Schüler/Professor um in die Verwendung von Klassen einzusteigen?
Re: Denkanstoss OOP
Verfasst: Freitag 29. Juli 2011, 21:37
von Piet Lotus
Hallo mcdwerner,
auch wenn der Thread schon lang ist, hier vielleicht noch mal eine allgemeinere Anmerkung zu OOP. Allgemein kann man sagen, dass Attribute und Methoden, die sich verschiedene Objekte teilen können in eine Oberklasse "geschoben" werden können. Diese verschiedenen Objekte können durch Vererbung diese Attribute und Methoden erben und man spart sich so eine Menge ("Tipp-")Arbeit. Die abgeleiteten Klassen, d.h. die Klassen, die Erben können dann die geerbten Attribut und Methoden noch um eigene spezifische Daten und Methoden erweitern. Man braucht nicht von einer Klasse erben, wenn man mit den zur Verfügung stehenden Attributen und Methoden auskommt. Dann bildet man "nur" eine Instanz der Klasse. Das ist nun sehr theoretisch. In deinem Beispiel könnte man sich eine (Ober-)klasse "Attraktionen" denken, mit den Attributen "name","von","bis","ort","entfernung","eintrittspreis", usw. Du könntest jetzt direkt die Instanzen Strand1, Strand2 usw. bilden. Oder wenn du z.B. Fallschirmspringen willst, bräuchtest du vielleicht das Attribut "mut_erfordert". Dann könntest du von "Attraktionen" den "name","von",usw, erben und ergänzt einfach das Attribut "mut_erfordert". In Bezug auf dein Beispiel Abseits der Schiene, könnte man annehmen, dass es eine Klasse "Mensch" mit den Attributen "name","größe","gewicht","alter","geschlecht" gibt, die für alle Lehrer/Schüler/Professoren gebraucht werden könnten. Wenn du mit diesen Attributen auskommst,dann bildest du halt nur Instanzen. Muss der Professor aber noch "prüfungen_abnehmen" oder der Schüler "schulpflichtig" sein, dann kannst du die Klasse "Mensch" als Oberklasse betrachten und Schüler und Professor durch Vererbung spezifisch erweitern.
Hoffe, das hilft und verwirrt nicht...
Viele Grüße
Piet