Seite 1 von 2
Sortieren von Objekten
Verfasst: Montag 8. Juni 2009, 18:33
von Aeron
Hallo,
hier erstmal mein Code:
Code: Alles auswählen
class Highscore(list):
HighscoreEntry=[]
def __init__(self, HighscoreEntry):
self.HighscoreEntry+=[HighscoreEntry]
def PlayerAverageScore(self, p):
count_scores=0
total_score=0
for entry in self.HighscoreEntry:
if (p==entry.PlayerName):
count_scores+=1
total_score+=int(entry.Score)
if(count_scores>0):
return '%.2f'%(round(float(total_score)/float(count_scores), 2))
else:
return 0
def TotalAverageScore(self):
count_scores=0
total_score=0
for entry in self.HighscoreEntry:
count_scores+=1
total_score+=int(entry.Score)
if(count_scores>0):
return '%.2f'%(round(float(total_score)/float(count_scores), 2))
else:
return 0
def SortHighscore(self):
self.sort()
class HighscoreEntry(Highscore):
obj_counter=0
def __init__(self, n, s, d):
self.PlayerName=n
self.Score=s
self.Date=d
self.obj_counter+=1
def __del__(self):
self.obj_counter-=1
def __lt__(self, other):
return self.Score < other.Score
def __le__(self, other):
return self.Score <= other.Score
def __eq__(self, other):
return self.Score == other.Score
def __ne__(self, other):
return self.Score != other.Score
def __gt__(self, other):
return self.Score > other.Score
def __ge__(self, other):
return self.Score >= other.Score
def getPlayerName(self):
return self.PlayerName
def getScore(self):
return self.Score
def getDate(self):
return self.Date
file = open('../highscore.txt','r')
i=0;
Entry={}
for line in file:
data=string.split(line, ',')
Entry[i]=HighscoreEntry(data[0], data[1], data[2])
h=Highscore(Entry[i])
i+=1
file.close();
Ich habe eine Highscore-Klasse die aus einer Textdatei gefüllt wird und möchte nun die einzelnen Einträge nach den Punkten also nach "Score" sortieren. Ich habe dafür die MagicMethods überschrieben, aber wenn ich h.sort() aufrufe tut sich nichts an der Reihenfolge ändern. Wisst ihr woran das liegt, könnt ihr mir irgendwie weiterhelfen? Wäre echt super!
Verfasst: Montag 8. Juni 2009, 18:34
von Dill
Verfasst: Montag 8. Juni 2009, 18:43
von Dill
ich frage mich grade: wie würde man denn in python von int erben?
int ist ja ein type. und eine wrapper-klasse scheint es nicht zu geben. muss ich da mit diesem metaclass-zauber hantieren?
also konkret wie würde man das machen wenn man hier so eine highscore-klasse hat die die ganzen magic-member von int implementieren soll...
Verfasst: Montag 8. Juni 2009, 18:45
von Aeron
Mhh ich blicke jetzt irgendwie nicht ganz was ich in __cmp__ genau implementieren muss...
Code: Alles auswählen
def __cmp__(self, other):
return cmp(self.Score, other.Score)
soetwas würde ich jetzt aus deinem Link entnehmen, was ich noch machen müsste, aber das funktioniert nicht
Nach
http://openbook.galileocomputing.de/pyt ... 12_003.htm
hab ich auch folgendes probiert:
Code: Alles auswählen
def __cmp__(self, other):
if(self.Score>other.Score):
return 1
if(self.Score==other.Score):
return 0
if(self.Score>other.Score):
return -1
leider auch ohne Erfolg

Aber da stand halt das die Methode halt entsprechende Werte zurückgeben muss und so, darum weiß ich jetzt eigentlich überhaupt nicht, was die Methode zurückliefern soll. Weil das ja nicht funktioniert. Könntest du mir noch nen kleinen Hinweis geben ^^?
Verfasst: Montag 8. Juni 2009, 18:47
von Aeron
Ah meinst du, dass ich die Elemente bevor ich sie verlgeiche nach Integer casten muss? Damit sie auch als Zahl wargenommen werden?
Verfasst: Montag 8. Juni 2009, 18:57
von Dill
was ist denn das problem? "geht nicht" hilft nicht.
nein, du musst die nicht casten, wenn die vom gleichen typ sind (müssten sie ja) und sie sich vergleichen lassen. (das nehme ich mal an)
Verfasst: Montag 8. Juni 2009, 18:57
von derdon
Dill hat geschrieben:ich frage mich grade: wie würde man denn in python von int erben?
So:
Code: Alles auswählen
>>> class MyInt(int):
... def __new__(cls, val):
... return int.__new__(cls, val)
... def __str__(self):
... return 'my int has the value: %d' % self
...
>>> my_int = MyInt(42)
>>> my_int
42
>>> print my_int
my int has the value: 42
Verfasst: Montag 8. Juni 2009, 18:58
von cofi
Hinweis 1: Lass die Klammern bei Vergleichen weg.
Hinweis 2: Benutze keine Strichpunkte.
Hinweis 3: Überschreibe keine built-ins (`file`)
Hinweis 4: Schau dir mal [wiki]PEP 8 (Übersetzung)[/wiki] oder
das Original an
Hinweis 5: Vergiss das Openbook, wenn du wissen willst warum such im Forum nach Openbook
Hinweis 6: Langen Code bitte nach
http://paste.pocoo.org/ auslagern.
Eigentlich müsste die `sort`-Methode rich comparison benutzen, die du ja
implementiert hast ... Welche Version benutzt du denn?
Daneben wüsste ich gerne, warum du von `list` ableitest und nicht einfach composition benutzt (eine Liste als Attribut).
@Dill für `int` muss man sich um `__new__` kümmern:
http://www.voidspace.org.uk/python/webl ... html#e1014
Verfasst: Montag 8. Juni 2009, 18:59
von BlackJack
@Aeron: Vergiss den Tipp von Dill "halb". Daran liegt's nicht, aber die `__cmp__()`-Methode zu implementieren ist weniger als die ganzen anderen Methoden zum Vergleichen zu implementieren.
Dein Problem scheint mir eher zu sein *was* Du sortierst. Du erbst von `list` und *das* Exemplar wird dann auch sortiert, nur sind da gar keine Einträge drin, denn die packst Du in das Klassenattribut `HighscoreEntry`.
Der ganze Klassenentwurf ist Murks. Einen Konstruktor nur dazu zu missbrauchen um eine Element zu einem Klassenattribut hinzuzufügen ist falsch. Das `Highscore` von `list` erbt, wird nirgends verwendet, also kann man das auch bleiben lassen. Die Einträge sollten in einem Attribut auf dem Exemplar, also für jedes Exemplar verschieden, gespeichert werden.
Das runden in `PlayerAverageScore` ist überflüssig. Und je nach Situation eine Zahl oder eine Zeichenkette zurückzugeben ist eine schlechte Idee. Der Rückgabewert sollte möglichst immer vom gleichen Typ sein.
Die Namen entsprechen nicht der üblichen Konvention. Insbesondere Namen die mit einem Grossbuchstaben beginnen, sollten für Klassen vorbehalten bleiben.
`HighscoreEntry` sollte nicht von `Highscore` erben. Vererben drückt eine "ist-ein(e)"-Beziehung aus, und ein einzelner Eintrag ist eben keine ganze Bestenliste.
Der `obj_counter` scheint mir hier überflüssig, ausserdem funktioniert das so nicht, denn `__del__()` wird nicht garantiert und zuverlässig aufgerufen.
Die Namen der Argumente von den meisten Methoden sind zu kurz. Namen sollten auch was aussagen und nicht Fragezeichen beim Leser hinterlassen.
Die Getter sind in Python unüblich. Die Getter, die sporadischen Semikolons, und die Namensgebung machen mir den Eindruck, dass Du versuchst eine andere Sprache in Python zu schreiben. Python ist nicht C++ oder Java.
Warum ein Dictionary für `Entry` und keine Liste? Und warum speicherst Du die in einem Dictionary *und* dem Klassenattribut in `Highscore`?
Funktionen aus dem `string`-Modul, die es auch als Methoden auf Zeichenketten gibt, sollte man nicht mehr benutzen.
Verfasst: Montag 8. Juni 2009, 19:05
von Dill
huch, da war ichzu faul mir den code anzuschauen, dabei hätte schon ein blick in die erste zeile genügt...
danke don, das muss ich mir in eine ruhigen minute mal anschauen.
Verfasst: Montag 8. Juni 2009, 19:36
von Aeron
cofi hat geschrieben:Eigentlich müsste die `sort`-Methode rich comparison benutzen, die du ja
implementiert hast ... Welche Version benutzt du denn?
Daneben wüsste ich gerne, warum du von `list` ableitest und nicht einfach composition benutzt (eine Liste als Attribut).
Benutze Phython 2.6. Hatte jetzt von list abgeleitet weil sonst .sort() gar nicht implementiert war

Eine Liste habe ich doch mit HighscoreEntry=[] praktisch als Attribut in der Highscore-Klasse oder nicht?
Mhh habe die Veerbung jetzt entfernt und die Hinweise alle beachtet und zum großteil schon umgesetzt
Einen Konstruktor nur dazu zu missbrauchen um eine Element zu einem Klassenattribut hinzuzufügen ist falsch.
Wie kann ich das alternativ denn umsetzen wenn ich die beiden Klassen Highscore und HighscoreEntry behalten will?
Aber warum die Sortierung konkret nicht geht weiß hier keiner oder? Oder will es nur niemand verraten

?
h.sort kann ich jetzt nicht mehr aufrufen, wenn ich die Klassen mit
und
deklariere
Verfasst: Montag 8. Juni 2009, 19:45
von Dill
blackjack hat doch geschrieben warum es nicht funktioniert.
Verfasst: Montag 8. Juni 2009, 19:52
von BlackJack
@Aeron: Ich habe doch schon verraten warum es nicht funktioniert: Dein `sort()`-Aufruf sortiert eine leere Liste, die Du auch sonst gar nicht weiter verwendest.
Und ja, eine Liste hast Du als Attribut der Klasse. Die gehört aber bei einem ordentlichen OO-Entwurf nicht an die Klasse, sondern an ein Exemplar einer Bestenliste gebunden.
Wenn Du `sort()` auf einem `Highscore`-Exemplar aufrufen willst, dann muss es darauf halt auch implementiert werden. Vorzugsweise als delegation an das Attribut, dass die Elemente enthält. Wenn das eine Liste ist, dann kennt die ja auch eine `sort()`-Methode.
Verfasst: Montag 8. Juni 2009, 19:55
von cofi
Das `sort` hat nicht funktioniert, weil du unglaublich viele Sachen durcheinander geworfen hast.
Wenn du composition benutzt löst sich dein Problem in einem Logikwölkchen auf. Es nützt eben nichts, wenn man nur erbt.
Dein `sort` kannst du ganz einfach mit einem
haben (wobei self.entries deine Liste ist)
Dazu solltest du dir anschauen welche ``__*__`` Methoden du implementieren musst, dass sich deine Klasse wie eine Liste verhält (wobei die Methoden dann ein proxy zu der internen Liste sein sollten !).
ist ganz schlecht, weil das `old-style` ist, du solltest deine Klasse von `object` ableiten. Du solltest dir mal das Tutorial anschauen und am besten alles aus dem Openbook zu Klassen vergessen.
Verfasst: Montag 8. Juni 2009, 20:42
von numerix
cofi hat geschrieben: ist ganz schlecht, weil das `old-style` ist, du solltest deine Klasse von `object` ableiten. Du solltest dir mal das Tutorial anschauen und am besten alles aus dem Openbook zu Klassen vergessen.
Wobei die oldstyle/newstyle-Geschichte mit Python 3 ja hinfällig geworden ist, wenn ich das richtig verstanden habe.
Verfasst: Montag 8. Juni 2009, 20:48
von Aeron
Vielen Dank schonmal soweit, ich verstehe inzwischen wo das Problem liegt

Habe versucht das jetzt zu verbessern, indem ich schonmal die Liste mit den einzelnen Einträgen an ein Exemplar der Bestenliste gebunden habe. Hab die sort()-Methode auch schon eingebaut.
Allerdings wird jetzt immer nur ein Element gespeichert in den Objekten, also nur ein eintrag in der Bestenliste, wisst ihr woran das liegt? Bin ich auf dem richtigen Weg, das die Sortierung funktioniert oder denke ich immernoch falsch?
Code: Alles auswählen
class Highscore(object):
def __init__(self):
self.HighscoreEntry=[]
def AddEntry(self, Entry):
self.HighscoreEntry+=[Entry]
def PlayerAverageScore(self, p):
count_scores=0
total_score=0
for entry in self.HighscoreEntry:
if (p==entry.PlayerName):
count_scores+=1
total_score+=int(entry.Score)
if(count_scores>0):
return '%.2f'%(round(float(total_score)/float(count_scores), 2))
else:
return 0
def TotalAverageScore(self):
count_scores=0
total_score=0
for entry in self.HighscoreEntry:
count_scores+=1
total_score+=int(entry.Score)
if(count_scores>0):
return '%.2f'%(round(float(total_score)/float(count_scores), 2))
else:
return 0
def sort(self):
self.HighscoreEntry.sort()
class HighscoreEntry(object):
def __init__(self, n, s, d):
self.PlayerName=n
self.Score=s
self.Date=d
def __lt__(self, other):
return self.Score < other.Score
def __le__(self, other):
return self.Score <= other.Score
def __eq__(self, other):
return self.Score == other.Score
def __ne__(self, other):
return self.Score != other.Score
def __gt__(self, other):
return self.Score > other.Score
def __ge__(self, other):
return self.Score >= other.Score
def getPlayerName(self):
return self.PlayerName
def getScore(self):
return int(self.Score)
def getDate(self):
return self.Date
fobj = open('../highscore.txt','r')
i=0;
for line in fobj:
data=string.split(line, ',')
h=Highscore()
h.AddEntry(HighscoreEntry(data[0], data[1], data[2]))
i+=1
fobj.close()
Auslesen kann ich die Objekte doch mittels folgeder Schleife ausserhalb der Klassen oder?
als Beispiel für die Ausgabe der Namen.
Verfasst: Montag 8. Juni 2009, 20:55
von cofi
numerix hat geschrieben:Wobei die oldstyle/newstyle-Geschichte mit Python 3 ja hinfällig geworden ist, wenn ich das richtig verstanden habe.
Das schon, aber er benutzt ja noch 2.6
Entschuldige, aber an der Lesbarkeit deines Codes hapert es kräftig, deswegen werde ich nichts dazu sagen, bis du die bisherigen Hinweise auch umsetzt in deinem Code.
(Das Posten wird übrigens immer schwieriger, weil du deinen Code nicht auslagerst.)
Verfasst: Montag 8. Juni 2009, 21:00
von numerix
cofi hat geschrieben:numerix hat geschrieben:Wobei die oldstyle/newstyle-Geschichte mit Python 3 ja hinfällig geworden ist, wenn ich das richtig verstanden habe.
Das schon, aber er benutzt ja noch 2.6

Klar, sollte auch kein Einwand gegen deinen Hinweis dazu sein. Nur 'ne Anmerkung mit Blick nach vorne ...
Verfasst: Montag 8. Juni 2009, 22:50
von BlackJack
@Aeron: Geh doch den Quelltext auf Modulebene mal in Gedanken durch. Was passiert da bei jedem Schleifendurchlauf? Wieviele `Highscore`-Objekte brauchst Du? Wieviele erstellst Du?
Verfasst: Montag 8. Juni 2009, 22:57
von Aeron
Mhhh ich brauche ein Highscore-Objekt, das halt mehrere HighscoreEntry Objekte enthält. Und da war auch schon der Fehler warums nur ein Element gab, hab bei jedem Schleifendurchlauf ein neues Objekt unter glreichem Namen angelegt

Dann kann natürlich auch nur ein Element von HighscoreEntry drinnen sein! Super, DANKESCHÖN
richtig, ists die erstellung der Objekte dann so:
Code: Alles auswählen
h=Highscore()
for line in fobj:
data=string.split(line, ',')
h.AddEntry(HighscoreEntry(data[0], data[1], data[2]))
i+=1
fobj.close()
Sortieren will es allerdings immer noch nicht, schnüff
Weil zum beispiel meine Methode TotalAverageScore greift ja auch wieder auf die Liste der HighscoreEntry-Elemente zu und da funktioniert es auch. Also kann die Liste ja eigentlich nicht leer sein, oder was versteh ich da noch falsch?