@Tengel: Man muss ein bisschen vorsichtig mit den Begriffen sein, weil in Python Klassen auch Objekte sind. Die Attribute einer Klasse sind die Attribute auf dem Klassenobjekt, was nicht das gleiche ist wie die Attribute auf dem Exemplar (Instanz) einer Klasse. Allerdings sind die Klassenattribute auch über das Exemplar erreichbar, sofern sie auf dem Exemplar nicht durch ein Attribut auf dem Exemplar verdeckt werden:
Code: Alles auswählen
class A(object):
a = 42
b = 23
def __init__(self):
self.b = 4711
print A.a # 42
print A.b # 23
a = A()
print a.a # 42
print a.b # 4711
In `Stapel` wird doch gar nicht auf Attribute von `Karte` zugegriffen, weder auf die von der Klasse noch die eines Exemplars. Jedenfalls nicht direkt.
Anmerkungen zum Quelltext: Namen von Klassenattributen schreibe ich persönlich komplett in Grossbuchstaben wenn es sich um Konstanten handelt.
Die Default-Werte bei den Argumenten von `__init__()` würde ich weg lassen, denn ich sehe nicht was an einer Kreuz 2 so besonders ist, dass das die Karte ist, die jeder erwarten würde wenn man die Argumente weg lässt.
Die `__cmp__()` kann man mit Tupeln der Daten die eine Karte ausmachen und der `cmp()`-Funktion wesentlich einfacher machen. Wenn man `__cmp__()` (oder `__eq__()`) implementiert, sollte man insbesondere bei Wertdatentypen auch die `__hash__()`-Methode implementieren. Wertdatentypen sind solche, bei denen die Attribute, die den Gesamtwert des Objekts ausmachen, sich nicht mehr ändern. Eine passende `__hash__()`-Implementierung braucht man um die Objekte als Schlüssel in Wörterbüchern oder Elemente in `set()`\s zu speichern. Die Wertigkeit von Farbe und Rand beim Vergleich würde ich übrigens umdrehen.
Der `Stapel` weiss IMHO zu viel über die Karten weil er das Kartenspiel in der `__init__()` erstellt. Man könnte einen Kartenstapel schreiben ohne dass der etwas darüber wissen muss wie die einzelnen Karten aussehen. Also einen der für Karten mit Farbe und Rang genau so funktioniert, wie für UNO-Karten, oder Quartett, oder andere Kartenarten.
Das erzeugen eines Kartenspiels wäre robuster, wenn es sich an den Rang- und Farbdaten orientieren würde, statt die Anzahlen hart als Zahlen in den Quelltext zu schreiben. Wenn man ein Romme-Spiel erzeugen möchte, müsste man sowohl die Liste mit den Rängen, als auch die Anzahl der Schleifendurchläufe anpassen, statt nur die Ränge.
Code: Alles auswählen
from itertools import imap
from random import shuffle
class Karte(object):
FARB_NAMEN = ['Kreuz', 'Karo', 'Herz', 'Pik']
RANG_NAMEN = [
'Ass', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Bube', 'Dame',
'König',
]
def __init__(self, farbe, rang):
self.farbe = farbe
self.rang = rang
def __str__(self):
return self.FARB_NAMEN[self.farbe] + '-' + self.RANG_NAMEN[self.rang]
def as_tuple(self):
return (self.rang, self.farbe)
def __cmp__(self, other):
return cmp(self.as_tuple(), other.as_tuple())
def __hash__(self):
return hash(self.as_tuple())
@classmethod
def erzeuge_kartenspiel(cls):
return Stapel(
[
cls(f, r)
for f in xrange(len(cls.FARB_NAMEN))
for r in xrange(len(cls.RANG_NAMEN))
]
)
class Stapel(object):
def __init__(self, karten):
self.karten = karten
def __str__(self):
return '\n'.join(imap(str, self.karten))
def mischen(self):
shuffle(self.karten)
def ziehe_karte(self):
return self.karten.pop()
def main():
stapel = Karte.erzeuge_kartenspiel()
stapel.mischen()
print stapel
print stapel.ziehe_karte()
if __name__ == '__main__':
main()