Seite 7 von 9
Re: Gewinnspiel
Verfasst: Donnerstag 11. April 2013, 20:01
von Gary123456
Vor lauter Begeisterung habe ich das mal auf mein Programm angewendet und bin mir nicht zu 100% sicher, ob das stimmt (es funktioniert aber!)
Code: Alles auswählen
import easygui, random, sys
class Spiel:
def __init__(self, spielername):
self.name = spielername
self.liste = [
("Was ist Fifa13?", ["Ein Computerspiel", "Ein Monster", "Eine Uhrzeit"]),
("Was ist eine Computermaus?", ["Ein Steuerungsgeraet", "Eine Tastatur", "Ein Bildschirm"]),
("Test1", ["Test2", "Test3", "Test4"])
]
self.punkte = 0
self.versuche = 3
self.geld = 0
def __str__(self):
hinweis = "Das ist ein klassisches 'Wer wird Millionär' Spiel"
return hinweis
def punkte_hinzufuegen(self, betrag): #Normal sind 100 Punkte
self.punkte += betrag
return self.punkte
def punkte_abziehen(self, betrag):
if self.punkte > 100:
self.punkte -= betrag
return self.punkte
else:
print "Sie haben das Spiel verloren!"
def geld_hinzufuegen(self, betrag):
self.geld += betrag
return self.geld
def geld_abziehen(self, betrag): #pro Frage wahrscheinlich 100 € weg
if self.geld >= 100:
self.geld -= betrag
return self.geld
else:
print "Sie haben das Spiel verloren!"
def punkte_anzeigen(self):
return self.punkte
def geld_anzeigen(self):
return self.geld
Re: Gewinnspiel
Verfasst: Donnerstag 11. April 2013, 21:52
von /me
Gary123456 hat geschrieben:
punkte_anzeigen ist der falsche Name für die Methode. Da wird nichts angezeigt, sondern nur ein Wert zurückgegeben.
Zudem ist die Methode überflüssig. Wenn du die Punkte haben willst, dann greif doch einfach direkt auf
name_der_spiel_instanz.punkte zu, statt den unnötigen Umweg zu gehen.
An einer anderen Stelle ist es ebenfalls merkwürdig. Die Methode
punkte_abziehen tut nicht nur das was ihr Name sagt, sondern gibt auch noch die neue Punktzahl als Wert zurück. Schlimmer noch, in der Methode mischst du wieder Ein-/Ausgabe mit Logik. Lass das Spiel ein Spiel sein und erledige Ausgaben außerhalb.
Re: Gewinnspiel
Verfasst: Donnerstag 11. April 2013, 22:17
von derdon
Was sollen die Kommentare "Normal sind …" und "pro Frage wahrscheinlich …"? Es ist zwar bekannt, dass Software in der Regel nicht-deterministisch ist, aber das so deutlich in den Kommentaren auszudrücken, ist doch ungewöhnlich

Also tu zumindest so, als ob sich dein Programm ganz verlässlich immer so verhält wie du es erwartest und schreibe konkretere Kommentare. Anstelle der magischen 100 bietet sich eine Klassenkonstante an, um den Code sowohl lesbarer als auch wartbarer zu machen.
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 09:00
von kbr
@Gary123456: Deinen Code habe ich mal etwas umgestellt. Das ist jetzt nur ganz rudimentär ohne __name__ == '__main__' etc. und soll Dir beispielhaft zeigen, wie Du Logik und IO trennen kannst, und dass für den Attributzugriff keineswegs getter und setter gebraucht werden. Und 'property' habe ich Dir deswegen auch eingebaut.
Code: Alles auswählen
FRAGEN = [
("Was ist Fifa13?",
["Ein Computerspiel", "Ein Monster", "Eine Uhrzeit"]),
("Was ist eine Computermaus?",
["Ein Steuerungsgeraet", "Eine Tastatur", "Ein Bildschirm"]),
("Test1",
["Test2", "Test3", "Test4"])
]
GRENZWERT = 100
class Spiel(object):
def __init__(self, spielername, fragen, grenzwert):
self.name = spielername
self.fragen = fragen
self.grenzwert = grenzwert
self.punkte = 0
def __str__(self):
return u"Das ist ein klassisches 'Wer wird Millionär' Spiel"
@property
def ist_zuende(self):
return self.punkte < self.grenzwert
# Beispiel:
# Erzeuge Spiel-Objekt mit Frageliste
spiel = Spiel('Gary', FRAGEN, GRENZWERT)
# direkter Zugriff auf Instance-Variable
spiel.punkte += 500
print spiel.punkte
# Ablaufkontrolle
if spiel.ist_zuende:
print 'Spiel verloren'
else:
print 'Spiel geht weiter'
# Stelle Fragen
for frage in spiel.fragen:
print frage
...
Das musst Du jetzt nur noch passend konstruieren. Elegant wäre es, wenn auch die Fragen Objekte mit Attributen wären, so dass Du etwas wie das folgende schreiben könntest:
Code: Alles auswählen
for frage in spiel.fragen:
print frage.fragetext
...
if antwort == frage.antwort:
spiel.punkte += 100
else:
spiel.punkte -= 100
if spiel.ist_zuende:
break
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 10:27
von Sirius3
@kbr: und hier machst Du zu viel Spiel-relevantes außerhalb der Spiel-Klasse.
Das Spiel soll selbst entscheiden, ob es weitere Fragen gibt, oder ob es zu Ende ist.
Das Spiel soll selbst entscheiden, was passiert, wenn eine Frage richtig oder falsch beantwortet wird:
Code: Alles auswählen
FRAGEN = [
("Was ist Fifa13?",
["Ein Computerspiel", "Ein Monster", "Eine Uhrzeit"]),
("Was ist eine Computermaus?",
["Ein Steuerungsgeraet", "Eine Tastatur", "Ein Bildschirm"]),
("Test1",
["Test2", "Test3", "Test4"])
]
GRENZWERT = 100
class Spiel(object):
def __init__(self, spielername, fragen, grenzwert):
self.name = spielername
self._fragen = fragen
self.grenzwert = grenzwert
self.punkte = grenzwert
def __str__(self):
return u"Das ist ein klassisches 'Wer wird Millionär' Spiel"
@property
def fragen(self):
for frage in fragen:
if self.punkte < self.grenzwert:
break
yield frage
def verarbeite_antwort(self, antwort):
self.punkte += 100 if antwort else -100
spiel = Spiel('Gary', FRAGEN, GRENZWERT)
# Stelle Fragen
for fragetext, antworten in spiel.fragen:
print fragetext
...
spiel.verarbeite_antwort(antwort == richtige_antwort)
print "Du hast jetzt %d Punkte" % spiel.punkte
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 11:01
von kbr
@Sirius3: Du hast ja recht und mit einer Antwort in diese Richtung hatte ich auch gerechnet, denn das Spiel-Objekt in meinem Beispiel hält im wesentlichen nur den Status fest - ganz rudimentär, so wie ich schrieb.
Aber lass Gary an einfachen Beispielen erst einmal die Nutzung von Klassen üben, eventuell auch für Fragen eine Klasse erstellen und dann, folgerichtig, auch die Spiellogik in die Klasse aufnehmen und dabei lernen, was Refactoring ist, und das dies ein beständiger Prozess bei der Softwareentwicklung darstellt.
Deine Erweiterung mag ihm später auch helfen, zuvor aber wirst Du ihm vermutlich erst einmal 'yield' erklären müssen. Und warum Du aus 'self.fragen' 'self._fragen' machen musstest, was Du zudem nicht verwendest.
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 12:25
von Gary123456
Hi,
@me)
Ja, da hast Du sicher Recht!
@derdon)
Eig ist es doch mein Bier, was ich in den Kommentaren schreibe.
@Sirius + kbr)
Mein Beispiel war nur ein kleiner Einstige, wie man Klassen genau verwendet. Es wird sicher nicht ins reale Programm einfließen, bis ich noch nicht die nötige Übung habe. Bis dahin werde ich zwar am Millionär-Spiel das üben, aber nicht einsetzen, bis der Code richtig ist. Und ich habe auch verstanden, was Ihr sagen wollt

Habe auch als Übung eine Bankklasse entwickelt und sie funktioniert, jedoch habe ich den Code nicht mehr.
Aber lass Gary an einfachen Beispielen erst einmal die Nutzung von Klassen üben, eventuell auch für Fragen eine Klasse erstellen und dann, folgerichtig, auch die Spiellogik in die Klasse aufnehmen und dabei lernen,
Richtig. Ich will an diesem "Millionär-Beispiel" üben. Obwohl - eig ist es ja das Hauptspiel.
Doch dann noch eine Frage an Dich, lieber Sirius:
Was erbst Du da?
Aber jetzt muss ich zu SQL rüber, aber keine Sorge, schulisch bedingt. Mir schreiben in gute 3 Wochen eine Arbeit und da will ich unbedingt gut sein

Daher - werde ich evtl. nicht mehr so viel Zeit haben. Wie lässt sich SQL eig in Python einsetzen?
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 13:38
von Sirius3
@kbr: Dass self._fragen nicht benutzt wird, ist der obligatorische Programmierfehler, weswegen man das gesamte Programm für unbrauchbar erklärt und genervt wegschmeißt.
@Gary123456: unter Python 2.x gibt es zwei verschiedene Arten von Klassen, klassische und neue. Neue haben erweiterte Funktionen und werden dadurch definiert, dass sie von »object« abstammen.
Python hat zu allen wichtigen Datenbanken Module zur Anbindung. Einfach mal google z.B. nach »python sqlite« fragen.
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 14:01
von Gary123456
Neue haben erweiterte Funktionen und werden dadurch definiert, dass sie von »object« abstammen.
Damit mkeinst Du noch so weitere Funktionen wie die init und str Methode?
Ich versteh immer mehr, dennoch versuche ich alles langsam anzugehen

Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 17:21
von Gary123456
Ich will jetzt auf Nummer sicher gehen. Ich werde euch meinen Gedankenschritt sagen, wie ich bei einer Erstellung einer Klasse vorgehen würde.
- Zuerst überlege ich mir, welche Eigenschaften das Spiel an sich hat (z.B. Geld, Punkte etc. => Attribute). Die lege ich in die __init__ Funktion
- danach überlege ich mir, was das Spiel können muss und erstelle Methoden.
Eine kurzer Gedankenschritt, sollte aber richtig sein

Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 17:45
von cofi
Gary123456 hat geschrieben:Neue haben erweiterte Funktionen und werden dadurch definiert, dass sie von »object« abstammen.
Damit mkeinst Du noch so weitere Funktionen wie die init und str Methode?

Nein, Funktionen im Sinne von "Funktionalitaet". Beispielsweise unterstuetzen sie das Deskriptor-Protokoll, Properties, Metaklassen, ...
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 17:54
von Gary123456
Nein, Funktionen im Sinne von "Funktionalitaet". Beispielsweise unterstuetzen sie das Deskriptor-Protokoll, Properties, Metaklassen, ...
Ich denke, dass ist für meinen derzeitigen Wissenstand unwichtig

Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 18:18
von Gary123456
Das sind meine Attribute, die ich in der __init__ Funktion angeben werde. Das ist mal vorerst der Plan.
Von den Methoden hätte ich mir 4 überlegt:
- Punkte abziehen
- Punkte erhalten
- Geld abziehen
- Geld erhalten
Diese Methoden könnte man zwar mit self.punkte += betrag abkürzen, dennoch finde ich Methoden übersichtlicher.
Die reine Klasse hier:
Code: Alles auswählen
import easygui, random, sys
class Spiel:
def __init__(self, spielername, punkte, geld, schwierigkeit, level, thema, fragen):
self.spielername = spielername
self.punkte = punkte
self.geld = geld
self.schwierigkeit = schwierigkeit
self.level = level
self.thema = thema
self.fragen = fragen
def __str__(self):
nachricht = "Das ist ein Spiel" #Wird zur Hilfe ausgebaut!
return nachricht
def punkte_abziehen(self, betrag):
self.punkte -= betrag
def punkte_aufnehmen(self, betrag):
self.punkte += betrag
def geld_abziehen(self, betrag):
self.geld -= betrag
def geld_aufnehmen(self, betrag):
self.geld += betrag
Ich denke, jetzt ist die Logik besser.
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 21:38
von cofi
Gary123456 hat geschrieben:Von den Methoden hätte ich mir 4 überlegt:
- Punkte abziehen
- Punkte erhalten
- Geld abziehen
- Geld erhalten
Kurzum: Die sind alle schlecht.
Bei Methoden musst du dich fragen, ob sie im Kontext der Klasse als Schnittstelle nach aussen Sinn machen. Alle 4 Methoden erfuellen das nicht, weil der Aufrufende hier folgende Fragen beantworten muss: "Ist die Frage richtig beantwortet?", "Wie viele Punkte ist diese Antwort wert?" usw.
Je nachdem wie man die Klasse benutzt kann das aber durchaus auch kein Problem sein, aber die Methoden haben ein weiteres Problem: Sie sind trivial, aber machen das Benutzen und Verstehen nicht einfacher.
Klassendesign ist leider etwas fuer das man Erfahrung braucht und das man nicht von jetzt auf gleich erlernen kann. Ein guter Ansatz ist sich in den anwendenden Code hineinzuversetzen und die Frage zu beantworten "Was muss die Klasse dafuer leisten koennen". Entwickle die Klasse nicht so, dass sie am Anfang direkt alle Anforderungen erfuellt (denn hier kennst du wahrscheinlich noch nicht alle), sondern iterativ, so dass sie alles leistet was sie leisten muss.
@__str__: Die Funktion soll eine "menschenlesbare Repraesentation" liefern, die den Status repraesentiert, also hier beispielsweise die Werte der Attribute.
Zu den Newstyle-Klassen: Dann benutze es nicht, aber tu dir den Gefallen und nutze sie einfach.
Re: Gewinnspiel
Verfasst: Freitag 12. April 2013, 22:13
von snafu
Klassen sollten vor allem Funktionalität liefern. Sie sollen nicht ihre (internen) Attribute widergeben, sondern sie sollen damit *arbeiten*. Klassen erfüllen in erster Linie Aufgaben. Natürlich sind sie manchmal auch ein Datenspeicher und natürlich sind auch gewisse Getter-Methoden in Ordnung. Es geht aber vor allem darum, dass die Klasse tatsächlich etwas tut und nicht nur verwaltet.
Re: Gewinnspiel
Verfasst: Samstag 13. April 2013, 09:14
von Gary123456
Hi,
Bei Methoden musst du dich fragen, ob sie im Kontext der Klasse als Schnittstelle nach aussen Sinn machen. Alle 4 Methoden erfuellen das nicht, weil der Aufrufende hier folgende Fragen beantworten muss: "Ist die Frage richtig beantwortet?", "Wie viele Punkte ist diese Antwort wert?" usw.
Meinst Du damit, dass man einen bestimmten Wert einsetzen muss (den Wert, der z.B. die Punkteanzahl bestimmt? Denn dann würde Frage2 wegfallen. Ich versteh nicht genau, was Du meinst.
Klassendesign ist leider etwas fuer das man Erfahrung braucht und das man nicht von jetzt auf gleich erlernen kann. Ein guter Ansatz ist sich in den anwendenden Code hineinzuversetzen und die Frage zu beantworten "Was muss die Klasse dafuer leisten koennen".
Klassen sind wie Baupläne. Daher will ich mit Hilfe dieser Klasse einen Bauplan für mein Projekt erstellen.
Entwickle die Klasse nicht so, dass sie am Anfang direkt alle Anforderungen erfuellt (denn hier kennst du wahrscheinlich noch nicht alle), sondern iterativ, so dass sie alles leistet was sie leisten muss.
Das versuche ich auch.
Zu den Newstyle-Klassen: Dann benutze es nicht, aber tu dir den Gefallen und nutze sie einfach.
Wenn Du meinst, benutze ich sie auch.
Klassen sollten vor allem Funktionalität liefern. Sie sollen nicht ihre (internen) Attribute widergeben, sondern sie sollen damit *arbeiten*. Klassen erfüllen in erster Linie Aufgaben. Natürlich sind sie manchmal auch ein Datenspeicher und natürlich sind auch gewisse Getter-Methoden in Ordnung. Es geht aber vor allem darum, dass die Klasse tatsächlich etwas tut und nicht nur verwaltet.
Jep. Aber was ist denn bitteschön eine Getter-Methode?
Und:
In SQL kann man das in ER-Diagramme unterbringen. Wie kann ich das am Besten in Python umwandeln. Also ein Python Diagramm , dass Atribute und Methoden veranschaulicht. Das würde mir sicher sehr viel erleichtern.
Re: Gewinnspiel
Verfasst: Samstag 13. April 2013, 09:23
von kbr
Gary123456 hat geschrieben:Jep. Aber was ist denn bitteschön eine Getter-Methode?
Vergiss das erstmal. Aber das Stichwort 'property' ist ja schon gefallen. Behalte das einfach mal im Hinterkopf.
Gary123456 hat geschrieben:In SQL kann man das in ER-Diagramme unterbringen. Wie kann ich das am Besten in Python umwandeln. Also ein Python Diagramm , dass Atribute und Methoden veranschaulicht. Das würde mir sicher sehr viel erleichtern.
Das Stichwort hier heißt UML-Diagramm.
Re: Gewinnspiel
Verfasst: Samstag 13. April 2013, 09:58
von Gary123456
Vielen, vielen Dank!
Man könnte doch insgesamt zwei Klassen erstellen, eine für Spiel, und eine Klasse Spieler, die von Spiel erbt. Nun frägt man sich, ob es ohne Klassen besser gehen würde. Ich muss mir da mal ganz klare Gedanken machen.
Re: Gewinnspiel
Verfasst: Samstag 13. April 2013, 10:07
von Leonidas
Gary123456 hat geschrieben:Man könnte doch insgesamt zwei Klassen erstellen, eine für Spiel, und eine Klasse Spieler, die von Spiel erbt.
Vererbung ist eine "ist-ein"-Beziehung, aber ein Spieler ist kein Spiel, also macht die Vererbung da keinen Sinn.
Gary123456 hat geschrieben:Nun frägt man sich, ob es ohne Klassen besser gehen würde. Ich muss mir da mal ganz klare Gedanken machen.
Du kannst da durchaus eine Klasse nutzen, wenn du magst.
Re: Gewinnspiel
Verfasst: Samstag 13. April 2013, 10:14
von Gary123456
Du kannst da durchaus eine Klasse nutzen, wenn du magst.
Naja, die Frage ist ja was sinnvoller ist. Eine Klasse voller Attribute? Eine Klasse, die auch ohne Methoden auskommt, da mir keine sinnvollen einfallen?
Vererbung ist eine "ist-ein"-Beziehung, aber ein Spieler ist kein Spiel, also macht die Vererbung da keinen Sinn.
Jep. Du kannst aber zwei Klassen erstellen. Eine Spiel Klasse, die die Fragen verwaltet. Und eine Spieler Klasse, die Punkte, Geld etc. verwaltet und paar Methoden hat.