Der Python-Kurs: Methoden
Willemers Informatik-Ecke
Attribute Python-Kurs Vererbung

Methoden: Aufruf, Parameter und Rückgabe

Eine Methode ist eine Funktion, die sich auf ein Objekt bezieht. Darum wird die Methode auch immer über ein Objekt aufgerufen.
class Zahl:
    zahl = 5
    def inkrementiere(self):
        self.zahl = self.zahl + 1

z = Zahl()
print(z.zahl)
z.inkrementiere()
print(z.zahl)
Eine Methode benötigt immer einen Parameter, der auf den Inhalt des Objekts bezogen wird. Dieser wird üblicherweise self genannt. Sie könnten ihn auch this nennen, welches der Standard bei Java ist.

Über self muss jeder Zugriff auf die Objektvariablen, also die Attribute erfolgen.

Da der self-Parameter immer gesetzt sein muss, werden Sie zwei Parameter benötigen, wenn Sie einen Übergabewert benötigen. Beispielsweise benötigt die Methode erhoehe den Wert, um den das Attribut erhöht werden soll.

class Zahl:
    zahl = 5
    def inkrementiere(self):
        self.zahl = self.zahl + 1
    def erhoehe(self, diff):
        self.zahl = self.zahl + diff
z = Zahl()
print(z.zahl)
z.inkrementiere()
print(z.zahl)
z.erhoehe(5)
print(z.zahl)
Der gleiche Mechanismus tritt auf, wenn der Konstruktor einen Parameter übernehmen soll. Das folgende Beispiel definiert den Konstruktor __init__ mit dem Parameter self und einem weiteren Parameter vorgabe. Da hier vorgabe eine 5 zugewiesen wird, kann er mit einem expliziten Parameter oder ohne Parameter aufgerufen werden. Im zweiten Fall wird die 5 verwendet.
class Zahl:
    def __init__(self, vorgabe=5):
        self.zahl = vorgabe
Wenn die Methode einen Rückgabewert liefern soll, wird am Ende der Befehl return angegeben. Soll ein Objekt einer Klasse zurückgegeben werden, wird es üblicherweise notwendig sein, ein solches Objekt durch Aufruf des Konstruktors zu erzeugen. Die folgende Version von erhoehe wird das eigene Objekt verändern und dann ein neues Objekt mit dem erhöhten Wert zurückgeben.
    def erhoehe(self, diff):
        self.zahl = self.zahl + diff
        return Zahl(self.zahl)
Beim Aufruf kann durch Voranstellen einer Variablen das zurückgegebene Objekt in einer Variablen abgelegt werden. a und z sind dann zwei unabhänige Objekte.
z = Zahl()
a = z.erhoehe(5)
print(a.zahl) # enthält 5
print(z.zahl) # enthält 5
a.inkrementiere()
print(a.zahl) # enthält 11
print(z.zahl) # enthält 10
Soll beim Erhöhen der Zustand des eigenen Objekts nicht verändert werden, darf das eigene Attribut nicht verändert werden. Dann können lokale Variablen verwendet werden.
    def erhoehe(self, diff):
        zahl = self.zahl + diff
        return Zahl(zahl)
Die Variable zahl ohne self ist eine einfache lokale Variable. Sie könnte auch hugo oder sonstwie heißen. Sie berechnet sich aus dem objekteigenen Attribut zahl und dem Parameter diff. Diese wird zurückgegeben. Das Objekt selbst ändert sich nicht.
z = Zahl()
a = z.erhoehe(5)
print(a.zahl) # enthält 10
print(z.zahl) # enthält 5
a.inkrementiere()
print(a.zahl) # enthält 11
print(z.zahl) # enthält 5

Selbstdarstellung der Klasse mit __str__()

Wenn ein Objekt per print ausgegeben werden soll, sieht man eine etwas kryptische Zeile:
print(r4)
<__main__.Auto object at 0x7f9db21dff10>
Es zeigt an, dass r4 ein Objekt der Klasse Auto ist und das sein Speicher an der Stelle 0x7f9db21dff10 beginnt. In den meisten Fällen wollen Sie aber eher die Inhalte des Objekts sehen. Dazu schreiben Sie eine eigene Methode namens __str()__.

class Auto:
    def __init__(self, name, ps):
        self.name = name
        self.ps = ps
    def __str__(self):
        return "Name: "+self.name+" PS: "+str(self.ps)
Wir legen nun ein Objekt der Klasse an und geben es per print aus.
r4 = Auto("R4", 34)
print(r4)
Auf dem Bildschirm erscheint:
Name: R4 PS: 34
Der Hintergrund ist, dass die Funktion print die Funktion str verwendet, um ein Objekt anzuzeigen. Die Funktion str wiederum schaut, ob die Klasse eine Methode __str__ besitzt und ruft diese dann auf.

Beispiel Bruchrechnung

In Python ist es möglich, die Operatoren wie + oder / für die eigene Klasse selbst zu definieren. Um das zu veranschaulichen, definieren wir eine Klasse Bruch, die Erinnerungen an den Mathe-Unterricht in der Mittelstufe hochkommen lässt.

class Bruch:
    def __init__(self, z, n):
        self.zaehler = z
        self.nenner  = n
    def add(self, b):
        n = self.nenner * b.nenner
        z = self.zaehler*b.nenner + b.zaehler*self.nenner
        return Bruch(z, n)
    def __str__(self):
        return "{}/{}".format(self.zaehler, self.nenner)
Nun definieren wir zwei Brüche und addieren sie über die Methode add.
a = Bruch(1, 2)
b = Bruch(1, 4)
c = a.add(b)
print(c)
Auf dem Bildschirm erscheint:
6/8
Wenn Sie das kürzen, kommen Sie auf 3/4. Dazu kann man übrigens prima den größten gemeinsamen Teiler aus der Übungsaufgabe verwenden.

Aber schauen wir auf einige Dinge, die erst einmal kurios erscheinen.

  1. Die Methode add hat nur einen Parameter, obwohl eine Addition doch zwei Operanden hat.
    Der erste Operand ergibt sich aus dem Objekt a, über dass die Methode aufgerufen wird. Der zweite Operand ist der Parameter b
    c = a.add(b)
    
  2. Hinter return erscheint der Aufruf Bruch(z, n).
    Die beiden Operanden bleiben durch die Addition unverändert. Der Ergebniswert muss per return an c zurückgegeben werden. Also muss c ein neues Objekt erhalten und genau dieses wird durch den Aufruf von Bruch(z,n) erzeugt.

Selbstgebaute Operatoren

Python bietet die Möglichkeit, Operatoren für eigene Klassen zu definieren. Dazu muss der Programmierer Methoden implementieren, die als Magic Members bezeichnet werden. Deren Bezeichner beginnen und enden mit je zwei Unterstrichen.

Um das Pluszeichen zu überschreiben, wird die Methode __add__ verwendet. Den Rest können wir aus der Methode add von oben übernehmen.

class Bruch:
    def __init__(self, z, n):
        self.zaehler = z
        self.nenner  = n
    def __add__(self, b):
        n = self.nenner * b.nenner
        z = self.zaehler*b.nenner + b.zaehler*self.nenner
        return Bruch(z, n)
    def __str__(self):
        return "{}/{}".format(self.zaehler, self.nenner)
Der Aufruf erfolgt nun genau wie beim Addieren von ganzen Zahlen.
a = Bruch(1, 2)
b = Bruch(1, 4)
c = a + b
print(c)
Und natürlich kann die Methode __add__ auch direkt aufgerufen werden.
a = Bruch(1, 2)
b = Bruch(1, 4)
e = a.__add__(b)
print(e)

Übersicht über die Operator-Methoden

Neben dem Plus-Operator können eine Vielzahl von Operatoren realisiert werden.

Operator Methode
== __eq__()
!= __ne__()
<= __le__()
< __lt__()
>= __ge__()
> __gt__()
+ __add__()
- __sub__()
* __mul__()
/ __truediv__()
// __floordiv__()
[] __getitem__()

Die Methode __div__ von Python 2 wird nicht mehr unterstützt.

Die offizielle Dokumentation finden Sie hier:

Übungsaufgaben

Kürzen

Durch die verschiedenen Operationen kann es leicht dazu kommen, dass Brüche nicht optimal gekürzt sind. Ändern Sie die Klasse so, dass ein Bruch immer optimal gekürzt ist. Dazu könnte die Lösung der Übungsaufgabe größter gemeinsamer Teiler hilfreich sein.

Mathematische Operatoren

Implementieren Sie als weiteren mathematischen Operator die Multiplikation.

Sie können Subtraktion und Division recht einfach realisieren, indem Sie Addition und Multiplikation nutzen.

Vergleichsoperatoren

Implementieren Sie die Vergleichsoperatoren. Für Gleichheit werden Sie die beiden beteiligten Brüche kürzen müssen. Beim Kleiner-Größer-Vergleich werden Sie beide Brüche auf den gleichen Nenner bringen müssen.