Klasse von list erben oder nicht?

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.
Antworten
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Wenn es sich wie eine Liste verhalten soll, dann würde ich auch von einer Liste erben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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:

Code: Alles auswählen

class bla(list):
    def __init__(self):
        pass
ist bla ja sozusagen exakt derselbe Datentyp wie `list`.
Aber wie greife ich jetzt auf die Elemente zu usw?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Karl hat geschrieben:Wenn ich folgendes schreibe:

Code: Alles auswählen

class bla(list):
    def __init__(self):
        pass
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]``
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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 :o thx
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Karl hat geschrieben:Wie dann? Den Konstruktor einfach weglassen? :)
Ja, dazu hat man ja u.A. die Vererbung.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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 ;)
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.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

(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? :o
Warum geht das nicht automatisch? :(
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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? :o
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``.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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 :D
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?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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 :D
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.
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

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:

Code: Alles auswählen

cmp=lambda x,y: cmp(x, y)
Aber das macht ja genau das, was es sonst auch macht. Es soll ja nur einen Wert und nicht beide vergleichen :o Ich hab keine Ahnung, wie ich das machen soll.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

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
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

Cool, wusste gar nicht, dass es sowas gibt ;)
Vielen Dank, klappt wunderbar!
Antworten