OOP Tutorial

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
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Gibt es hier nicht einen sozialen Menschen der für youtube o. ä. mal ein Tutorial zu OOP/Klassen machen möchte? :>

Allein durch lesen komm ich da nicht vorwärts .... und die momentanen Tutorials dazu sind eher 0 8 15


Gruß
Tengel
xeike
User
Beiträge: 83
Registriert: Donnerstag 28. Februar 2013, 09:58

Tengel hat geschrieben:Allein durch lesen komm ich da nicht vorwärts .... und die momentanen Tutorials dazu sind eher 0 8 15
Welche Informationen fehlen dir denn?

Xe
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Hm - Schnittstellen - wie genau das mit dem Globalen Zugriff ist.
self bedeutet ja ein Objekt- der Klasse, oder eine Instanz? oder ist das dass selbe?

Wann genau muss ich mit other Arbeiten? Nur wenn es dabei um ein anderes Klassenobjekt geht? Muss das von der selben Klasse sein?

Warum war an meinem Gui falsch das in der gui die commands für die Trafficobjekte gegeben wurde? Wie soll das sonst gehen?

Code: Alles auswählen

class Karte():
    def __init__(self, farbe=0, rang=2):
        self.farbe = farbe
        self.rang = rang

    farb_namen = ["Kreuz", "Karo", "Herz", "Pik"]
    rang_namen = [None, "Ass", "2", "3", "4", "5", "6", "7", "8","9",
                  "10", "Bube", "Dame", "König"]

    def __str__(self):
        return Karte.farb_namen[self.farbe] + "-" + Karte.rang_namen[self.rang]

    def __cmp__(self, other):
        if self.farbe > other.farbe: return 1
        if self.farbe < other.farbe: return -1

        if self.rang > other.rang: return 1
        if self.rang < other.rang: return -1

        return 0


class Stapel():
    def __init__(self):
        self.karten = [ ]
        for farbe in range(4):
            for rang in range(1,14):
                karte = Karte(farbe, rang)
                self.karten.append(karte)

    def __str__(self):
        res = [ ]
        for karte in self.karten:
            res.append(str(karte))
        return "\n".join(res)

    def ziehe_karte(self):
        return self.karten.pop()



Wieso kommt die Stapelklasse an die Attribute einer anderen Klasse?
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Tengel hat geschrieben:self bedeutet ja ein Objekt- der Klasse, oder eine Instanz? oder ist das dass selbe?
self bedeutet erst einmal gar nichts. self wird aber per Konvention als Bezeichnername für den ersten Parameter einer Methode verwendet und enthält bei der Verwendung dann ein Exemplar (Instanz) der Klasse.
Tengel hat geschrieben:Wann genau muss ich mit other Arbeiten? Nur wenn es dabei um ein anderes Klassenobjekt geht? Muss das von der selben Klasse sein?
Auch other ist nur ein Name. Welches Objekt daran gebunden wird ist beliebig, allerdings wird dieser Bezeichnername tatsächlich häufig innerhalb der Parameterliste von Methoden verwendet wenn eine zweite Instanz übergeben wird.
Tengel hat geschrieben:Wieso kommt die Stapelklasse an die Attribute einer anderen Klasse?
Warum nicht? Genau darum geht es doch. Oder möchtest du Attribute schützen? Dann versieh deren Namen mit einem führenden Unterstrich und das ist dann ein Hinweis, dass es sich hier um ein Attribut handelt das nicht als öffentlicher Teil der Klasse betrachtet werden soll.
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Also selbst wenn ich self.xyz Werte in der Methode nicht durch return zurück gebe kann global darauf zugegriffen werden?
Bzw. wundert es mich ja das die Stapel Klasse auf rang und farb Zuweisung zugreifen kann obwohl ich die Klasse ja nur geschrieben hab - also ohne in der Main auch wirklich ein Objekt zuzuweisen.
Zuletzt geändert von Tengel am Freitag 26. April 2013, 13:34, insgesamt 1-mal geändert.
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Tengel hat geschrieben:Also selbst wenn ich self.xyz Werte in der Methode nicht durch return zurück gebe kann global darauf zugegriffen werden?
Was soll global heißen? Wenn man Zugriff auf das Klassen-Exemplar hat, dann kann man auch auf diese Variablen zugreifen. Kannst dir auch mal die Übersetzung des offiziellen Tutorials anschauen.
Zuletzt geändert von nomnom am Freitag 26. April 2013, 13:37, insgesamt 1-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ja. Auf jedes Attribut, das an ein Objekt gebunden ist, kann von überall her zugegriffen werden, ohne dass irgendwelche Beschränkungen bestehen. Sowas kann man übrigens auch leicht durch eigene Experimente (Testprogramm oder Python-Shell) herausfinden, bevor man solche Fragen stellt.
BlackJack

@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()
Tengel
User
Beiträge: 210
Registriert: Sonntag 17. März 2013, 12:29

Naja das was mich verwundert ist das

for farbe in ...
for rang in ...
was in Stapel() genutzt wird obwohl das Attribute von Karte() sind
BlackJack

@Tengel: Das sind doch keine Attribute von `Karte`‽ Attribute sind die Dinger wo man mit dem Punktoperator drauf zugreift. Die Schleifenvariablen haben halt die gleichen Namen wie die Attribute, wegen der gleichen Bedeutung, aber man könnte die auch komplett anders nennen. Wäre nur nicht so sinnvoll.

Aber selbst wenn man tatsächlich auf die Attribute zugreifen würde, das tut man doch *ständig* wenn man den Punktoperator verwendet. Und wie schon erwähnt wurde: Wenn man das nicht machen soll(te), dann stellt der Programmierer dem Attributnamen einen Unterstrich voran.
Antworten