Seite 1 von 1
Klasse von list erben oder nicht?
Verfasst: Freitag 18. April 2008, 11:06
von Karl
Hallo.
Ich schreibe gerade eine Klasse, die eigentlich nur als Behälter (Liste) für mehrere Objekte einer anderen Klasse dient und nur ein paar funktionen, wie zum Beispiel das hinzufügen/löschen und Sortieren braucht.
Also konkret handelt es sich um eine Liste, in der sich alle Spielkarten (die die Instanz der Spielkarten-Klasse sind) befinden.
Jetzt weiß ich aber grad nicht, ob die Klasse von `list` erben soll, oder nicht ... Im Prinzip ist es ja nur eine Liste, ich erstelle inerhalb der Klasse auch ein list-Objekt, in das alle Spielkarten reingeschrieben werden. Die anderen Methoden sind wie gesagt zum sortieren usw da, also zum Verwalten der Karten.
Verfasst: Freitag 18. April 2008, 11:33
von Leonidas
Wenn es sich wie eine Liste verhalten soll, dann würde ich auch von einer Liste erben.
Verfasst: Freitag 18. April 2008, 11:43
von Karl
Leonidas hat geschrieben:Wenn es sich wie eine Liste verhalten soll, dann würde ich auch von einer Liste erben.
Klare Antwort

Aber dann stellt sich mir das Problem: Ich hab im Prinzip keine Ahnung von dem Datentyp `list`.
Okay, ich kann mir mit help die Methoden anschauen, aber wie greife ich jetzt inerhalb der Klasse auf die Liste/deren Elemente zu? Also ... Die Klasse an sich ist ja die Liste, aber in welcher Variable und wie und wo sind die Daten gespeichert?
Wenn ich folgendes schreibe:
ist bla ja sozusagen exakt derselbe Datentyp wie `list`.
Aber wie greife ich jetzt auf die Elemente zu usw?
Verfasst: Freitag 18. April 2008, 11:50
von Leonidas
Karl hat geschrieben:Wenn ich folgendes schreibe:
Würde ich nicht machen, da du die Möglichkeit verlierst über den Konstruktor eine Liste in ``bla`` umzuwandeln.
Karl hat geschrieben:Aber wie greife ich jetzt auf die Elemente zu usw?
``self[index]``
Verfasst: Freitag 18. April 2008, 12:01
von Karl
Leonidas hat geschrieben:
Würde ich nicht machen, da du die Möglichkeit verlierst über den Konstruktor eine Liste in ``bla`` umzuwandeln.
Wie dann? Den Konstruktor einfach weglassen?

Und eigentlich will ich ja auch nicht jede beliebige Liste in ``bla`` umwandeln, höchstens Listen, die nur Elemente vom typ ``blubb`` haben, da ich nur Elemente vom typ ``blubb`` in der Liste speichern will
Leonidas hat geschrieben:``self[index]``
Logisch

thx
Verfasst: Freitag 18. April 2008, 14:04
von EyDu
Karl hat geschrieben:Wie dann? Den Konstruktor einfach weglassen?

Ja, dazu hat man ja u.A. die Vererbung.
Verfasst: Freitag 18. April 2008, 14:25
von Leonidas
Karl hat geschrieben:Und eigentlich will ich ja auch nicht jede beliebige Liste in ``bla`` umwandeln, höchstens Listen, die nur Elemente vom typ ``blubb`` haben, da ich nur Elemente vom typ ``blubb`` in der Liste speichern will
Dann schreib den Konstruktor wenigstens sinnvoll, d.h. die Argumente checken ob sie vom passenden Typ sind und dann den Parent-Konstruktor aufrufen.
Naja, eigentlich ist __init__ so gesehen auch kein Konstruktor, sondern eher ein Initialisierer.
Verfasst: Freitag 18. April 2008, 14:26
von Karl
EyDu hat geschrieben:Karl hat geschrieben:Wie dann? Den Konstruktor einfach weglassen?

Ja, dazu hat man ja u.A. die Vererbung.
Jo

Okay, das klappt doch besser, als ich dachte

Perfekt, danke
Edit: Aber wie kann ich jetzt erreichen, dass in der Liste nur ein Datentyp (der meiner Kartenklasse) zugelassen wird? Ich will ja schön fleißig alle Fehlerquellen vermeiden oder abfangen können

Verfasst: Freitag 18. April 2008, 15:26
von BlackJack
@Karl: Dann nimm eine andere Programmiersprache. So etwas ist in Python unüblich. Somit würdest Du verhindern, dass man Objekte eines anderen Typs in Deine Liste steckt, die sich aber genau so verhalten wie von Karten erwartet wird.
Verfasst: Freitag 18. April 2008, 15:35
von Leonidas
Karl hat geschrieben:Edit: Aber wie kann ich jetzt erreichen, dass in der Liste nur ein Datentyp (der meiner Kartenklasse) zugelassen wird? Ich will ja schön fleißig alle Fehlerquellen vermeiden oder abfangen können

Wie BlackJacks sagte ist sowas in Python unüblich. Man würde es in Python 2.x so implementieren, dass man ``__init__`` überschreibt, dort die übergebenen werte testet und mit diesen dann ``list.__init__`` aufruft.
Verfasst: Freitag 18. April 2008, 15:36
von Karl
BlackJack hat geschrieben:@Karl: Dann nimm eine andere Programmiersprache. So etwas ist in Python unüblich. Somit würdest Du verhindern, dass man Objekte eines anderen Typs in Deine Liste steckt, die sich aber genau so verhalten wie von Karten erwartet wird.
Naja, stimmt schon. Du beziehst dich wohl auf den Spruch mit der Ente und dem Frosch, oder wie das war ;p wenn der Frosch quakt wie eine Ente, ist er eine Ente.
Wenn ich aber jetzt einen Integer reinschmeiße, dann führt das früher oder später, nämlich dann, wenn der Integer sich anders verhält als meine Karten, zu einem Error.
Sowas wie string bla = "blubb" vermisse ich irgendwie schon ab und zu ;o
Es ist halt nunmal Fakt, dass in einen Kartenstapel nur Karten gehören und keine Frösche oder Enten. Spätestens wenn ich den Frosch im Deck habe und wissen will, was für einen Rang er hat, und ob ich jetzt ein Full House hab, stimmt irgendwas nicht mehr ;o
Aber naja ... Wenn du meinst dass es in Python einfach unüblich ist, lass ich's einfach mal so? Und wenn mir wer n Frosch in's Deck schmeißt, selbst schuld oO
Verfasst: Freitag 18. April 2008, 16:36
von Karl
(Sorry, dass ich einen neuen Post erstelle, aber ich hab Angst, dass er sonst nicht wahrgenommen wird :p)
Ich habe ja jetzt eine Klasse, die von ``list`` erbt.
Alles schön und gut, aber:
Code: Alles auswählen
class Blubb(list):
# ...
x = Blubb()
y = Blubb()
x.append(Card(n, m))
y.append(Card(n, m))
#...
a = x + y
print a
So, jetzt erklär ich mal das Problem:
x ist eine Instanz von Blubb, y ebenso.
a (= x + y) reagierte auf print plötzlich ganz anders, also hab ich mal type(a) gemacht und siehe da ... a ist wieder eine Liste oO
Ich will aber, dass a auch eine Instanz von Blubb ist ;o
Wie mach ich das denn jetzt?
bei __add__ eine neue Instanz erstellen und die mit beiden Listen füllen und dann returnen?

Warum geht das nicht automatisch?

Verfasst: Freitag 18. April 2008, 16:45
von Leonidas
Karl hat geschrieben:siehe da ... a ist wieder eine Liste oO
Ich will aber, dass a auch eine Instanz von Blubb ist ;o
Wie mach ich das denn jetzt?
bei __add__ eine neue Instanz erstellen und die mit beiden Listen füllen und dann returnen?

Warum geht das nicht automatisch?

Weil ``x + y`` eigentlich ``x.__add__(y)`` ist und ``__add__`` ist in Blubb nicht implementiert, also geht er über die MRO in die Elternklassen, wo ``list.__add__`` ist, welches logischerweise eine Liste zurückgibt und kein ``Blubb``.
Verfasst: Freitag 18. April 2008, 16:52
von Karl
Leonidas hat geschrieben:Weil ``x + y`` eigentlich ``x.__add__(y)`` ist und ``__add__`` ist in Blubb nicht implementiert, also geht er über die MRO in die Elternklassen, wo ``list.__add__`` ist, welches logischerweise eine Liste zurückgibt und kein ``Blubb``.
Ahh, ergibt Sinn

Dann mach ich's eben so:
Code: Alles auswählen
def __add__(self, other):
new = Blubb()
for n in xrange(len(self)):
new.append(self[n])
for m in xrange(len(other)):
new.append(other[m])
return new
Oder geht das noch kürzer?
Naja ich glaub ich hab euch für's erste genug mit Listen gequält

Nur eine Frage noch:
Wenn ich in ``Bla`` 2 Eigenschaften definiere, ``x`` und ``y``, beide sind Integer, dann sortiert ``Blubb.sort()`` die Elemente anscheinend nach diesen Eigenschaften (Die geerbte sort()-Funktion). Aber wie kann dem Teil sagen, dass er nur nach ``x`` oder nur nach ``y`` sortieren soll? Oder muss ich die Funktion dann auch wieder selbst schreiben?
Verfasst: Freitag 18. April 2008, 17:57
von EyDu
Karl hat geschrieben:Oder geht das noch kürzer?
Ja, du kannst auch direkt über die Elemente einer Liste iterieren. Außerdem habe ich mit "chain" noch eine Schleife draus gemacht:
Code: Alles auswählen
import itertools
def __add__(self, other):
new = Blubb()
for e in itertools.chain(self, other)
new.append(e)
return new
Karl hat geschrieben:Naja ich glaub ich hab euch für's erste genug mit Listen gequält

Aber wie kann dem Teil sagen, dass er nur nach ``x`` oder nur nach ``y`` sortieren soll? Oder muss ich die Funktion dann auch wieder selbst schreiben?
"sort" hat eine "key"-Parameter, schau dir das einfach mal in der Doku an. Für kompliziertere Fälle steht auch noch der "cmp"-Parameter zur verfügen, den brauchst du in diesem Fall aber nicht.
Verfasst: Freitag 18. April 2008, 18:17
von Karl
Ich steh da mit dem Key Parameter völlig auf dem Schlauch.
als Beispiel hab ich nur key=str.lower() gefunden oO das hilft mir ziemlich wenig.
Bei cmp hab ich mal was mit lambda versucht:
Aber das macht ja genau das, was es sonst auch macht. Es soll ja nur einen Wert und nicht beide vergleichen

Ich hab keine Ahnung, wie ich das machen soll.
Verfasst: Freitag 18. April 2008, 18:28
von audax
Code: Alles auswählen
In [5]: import operator
In [6]: test.sort(key=operator.itemgetter(1))
In [7]: print test
[(9, 91), (8, 92), (7, 93), (6, 94), (5, 95), (4, 96), (3, 97), (2, 98), (1, 99), (0, 100)]
In [8]: test.sort(key=operator.itemgetter(0))
In [9]: print test
[(0, 100), (1, 99), (2, 98), (3, 97), (4, 96), (5, 95), (6, 94), (7, 93), (8, 92), (9, 91)]
so zum beispiel.
Äquivalent dann für Attribute mit operator.attrgetter
Verfasst: Freitag 18. April 2008, 19:17
von Karl
Cool, wusste gar nicht, dass es sowas gibt

Vielen Dank, klappt wunderbar!