Eigene Klassen definieren

Eine Klasse ist eine Vorlage für ein Objekt. Wenn wir eine eigene Klasse definieren, dann können wir Objekte dieser Klasse erstellen. Dabei wird der Konstruktor der Klasse aufgerufen. Anschliessend können wir die Methoden, die wir in der Klasse definiert haben, über das erzeugte Objekt aufrufen.

Klasse

Die Klasse stellt die Vorlage für einzelne Objekte dar. Eine Klasse wird mit dem Schlüsselwort class definiert. Der Klassennamen wird mit einem Grossbuchstaben geschrieben (Konvention). Die Klasse definiert im Minimum die spezielle Methode __init__, auch genannt Konstruktor. Diese wird beim Erzeugen eines Objektes aufgerufen. Das Erzeugen eines Objektes geschieht über den Klassennamen, der wie eine Funktion aufgerufen wird:

class Dog:
    def __init__(self):
        print("Objekt vom Typ Hund erzeugt")

dog1 = Dog()
dog2 = Dog()

Im obigen Beispiel werden zwei Objekte vom Typ Dog erzeugt: dog1 und dog2. Beim Erzeugen wird jedesmal der Konstruktor aufgerufen: In der Shell steht also 2x «Objekt vom Typ Hund erzeugt»

Eigenschaften

Bei Eigenschaften eines Objektes handelt es sich um Variablen welche in der Klasse im Konstruktor gesetzt werden. Diese können für jedes Objekt andere Werte haben. In der Klasse drin greift man mit dem Schlüsselwort self und der Punktnotation auf die Eigenschaften zu.

class Dog:
    def __init__(self):
        self.name = "Wuffi"
        self.age = 5

dog1 = Dog()
print(dog1.name)
print(dog1.age)

dog2 = Dog()
dog2.name = "Waldemar"
dog2.age = 12
print(dog2.name)
print(dog2.age)

Methoden

Wir ergänzen unsere Klasse Dog um einige Methoden:

  • happy_birthday() – erhöht die Eigenschaft age des Objektes um eins
  • __str__() – eine spezielle Methode, welche automatisch von Python aufgerufen wird, wenn das Objekt in einen String konvertiert werden muss. (Im Beispiel ist das in der letzten Zeile, bei print(dog), der Fall.) Wir geben also eine Text-Darstellung unseres Hunde-Objektes zurück.
class Dog:
    def __init__(self):
        self.name = "Wuffi"
        self.age = 5

    def happy_birthday(self):
        self.age = self.age + 1

    def __str__(self):
        return("Ich bin ein Hund, heisse " + self.name + " und bin " + str(self.age) + " Jahre alt")

dog = Dog()
dog.happy_birthday()
dog.happy_birthday()
print(dog)

Es wird ein Objekt dog erzeugt. Nachdem 2x die Methode happy_birthday() aufgerufen wurde, hat nun die Eigenschaft age unseres Dog-Objektes den Wert 7. Die letzte Zeile gibt also den Text «Ich bin ein Hund, heisse Wuffi und bin 7 Jahre alt» auf der Shell aus.

In Python erhalten alle Methoden einer Klasse als erstes Argument einen Verweis auf sich selbst. Dieses Argument wird mit self bezeichnet. Es referenziert das aktuelle Objekt und bietet somit Zugriff auf die eigenen Eigenschaften und Methoden.

Konstruktor

Schön wäre, wenn wir dem Hunde-Objekt bereits beim Erzeugen einen beliebige Namen und Alter geben könnten. Dies ist möglich durch zusätzliche Argumente im Konstruktor. Im Beispiel wird ein Argument name verlangt – ohne Namen lässt sich kein Hunde-Objekt mehr erzeugen. Das Argument age hingegen ist optional; lässt man es weg, wird als Standard-Wert 0 genommen.

class Dog:
    def __init__(self, name, age=0):
        self.name = name
        self.age = age

    def happy_birthday(self):
        self.age = self.age + 1

    def __str__(self):
        return("Ich bin ein Hund, heisse " + self.name + " und bin " + str(self.age) + " Jahre alt")

dog1 = Dog("Wuffi")
dog1.happy_birthday()
dog1.happy_birthday()
print(dog1)

dog2 = Dog("Waldemar", 4)
print(dog2)

Das Programm erstellt zwei Dog-Objekte. Das erste print liefert: «Ich bin ein Hund, heisse Wuffi und bin 2 Jahre alt». Das zweite: «Ich bin ein Hund, heisse Waldemar und bin 4 Jahre alt»

Kapselung

Es gilt als unschön und kann zu Problemen führen, wenn man die Eigenschaften eines Objektes direkt anspricht. Deshalb definiert man Eigenschaften und auch Methoden, die nur Klassenintern verwendet werden sollen, als «private». In Python erreicht man das durch Voranstellen eines Underscores.
Damit man weiterhin z.B. das Alter des Hundes abfragen kann, führt man ein Methode age() ein, welche das Alter zurückgibt. Ändern kann man das Alter ja über die Methode happy_birthday().
Möchte man eine Eigenschaft setzen und lesen können, so muss man entweder zwei verschiedene Methoden schreiben, oder man muss das Attribut optional angeben: dog.name("Waldemar") ändert den Namen des Hundes während dog.name() den aktuellen Namen zurückliefert.

class Dog:
    def __init__(self, name, age=0):
        self._name = name
        self._age = age

    def happy_birthday(self):
        self._age = self._age + 1

    def age(self):
        return self._age

    def name(self, name = None):
        if name:
            self._name = name
        else:
            return self._name

    def __str__(self):
        return("Ich bin ein Hund, heisse " + self._name + " und bin " + str(self._age) + " Jahre alt")

dog = Dog("Wuffi")
dog.happy_birthday()
print(dog.age())
print(dog.name())

dog.name("Waldemar")
print(dog)