CodeGym /Kurse /Python SELF DE /Operatorüberladung

Operatorüberladung

Python SELF DE
Level 20 , Lektion 0
Verfügbar

6.1 Magische Methoden

Die Überladung von Operatoren in Python ermöglicht es, das Verhalten von eingebauten Operatoren (wie z.B. +, -, *, /) für benutzerdefinierte Klassen zu definieren oder zu ändern. Dies geschieht mithilfe von speziellen Methoden, die auch als magische Methoden bezeichnet werden.

Zum Beispiel kannst du in deiner Klasse Vergleichsoperatoren überladen:

Operator Methode ohne Unterstrich Methodensignatur
== eq() __eq__(self, other)
!= ne() __ne__(self, other)
< lt() __lt__(self, other)
<= le() __le__(self, other)
> gt() __gt__(self, other)
>= ge() __ge__(self, other)

Angenommen, du hast deine eigene Klasse geschrieben und möchtest, dass die Objekte deiner Klasse genauso verglichen werden, wie du es möchtest. Du musst einfach in deiner Klasse die Methode „__eq__“ implementieren, und Python wird sie jedes Mal aufrufen, wenn Objekte deiner Klasse im Code verglichen werden.

Beispiel:


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
        
# Verwendung
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2)  # Gibt aus: True
print(v1 == v3)  # Gibt aus: False

Jedes Mal, wenn du zwei deiner Objekte vergleichst, prüft Python, ob sie eine implementierte Funktion „__eq__“ haben. Falls ja, wird diese aufgerufen. Wenn nicht, werden einfach die Referenzen der Objekte verglichen.

Im obigen Beispiel ist faktisch geschrieben (nur sollte noch eine Prüfung auf das Vorhandensein der Methode hinzugefügt werden):


# Verwendung
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2))  # Gibt aus: True
print(v1.__eq__(v3))  # Gibt aus: False

6.2 Liste aller Operatoren

Es gibt insgesamt 6 Gruppen von Operatoren, die überladen werden können.

Arithmetische Operatoren:

Operator Methode ohne Unterstrich Methodensignatur
+ add __add__(self, other)
- sub __sub__(self, other)
* mul __mul__(self, other)
/ truediv __truediv__(self, other)
// floordiv __floordiv__(self, other)
% mod __mod__(self, other)
** pow __pow__(self, other)

Vergleichsoperatoren:

Operator Methode ohne Unterstrich Methodensignatur
== eq __eq__(self, other)
!= ne __ne__(self, other)
< lt __lt__(self, other)
<= le __le__(self, other)
> gt __gt__(self, other)
>= ge __ge__(self, other)

Logische Operatoren:

Operator Methode ohne Unterstrich Methodensignatur
& and __and__(self, other)
| or __or__(self, other)
^ xor __xor__(self, other)
~ invert __invert__(self)

Indexierungs- und Slice-Operatoren:

Operator Methode
obj[key] __getitem__(self, key)
obj[key] = value __setitem__(self, key, value)
del obj[key] __delitem__(self, key)

Unäre Operatoren:

Operator Methode
- __neg__(self)
+ __pos__(self)
abs() __abs__(self)
~ __invert__(self)

Zuweisungsoperatoren:

Operator Methode
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

Vielleicht ist Python deshalb so langsam – jedes Mal, bevor ein Operator ausgeführt wird, sucht es nach einer entsprechenden Funktion in der Klasse und allen seinen Elternklassen. Dafür kann man den kompaktesten Code der Welt schreiben :)

6.3 Der Indexierungsoperator

Dass man Objekte vergleichen oder Mengen subtrahieren kann, ist in gewissem Sinne offensichtlich. Und du wirst das selbst herausfinden, wenn du eine Klasse schreibst, die logische oder mathematische Operationen über sie impliziert.

Ich möchte mit dir solch ein interessantes Beispiel besprechen – den Indexierungsoperator. Lass uns gleich mit einem Beispielcode beginnen:


class CustomList:
    def __init__(self, data):
        self.data = data
        
    def __getitem__(self, index):
        return self.data[index]
        
    def __setitem__(self, index, value):
        self.data[index] = value
        
    def __delitem__(self, index):
        del self.data[index]
        
    def __repr__(self):
        return repr(self.data)
        
# Verwendung
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1])  # Gibt aus: 2
c_list[1] = 10
print(c_list)  # Gibt aus: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list)  # Gibt aus: [1, 3, 4, 5]

Hier sehen wir ein Beispiel für drei Operationen:

  • Lesen von Daten über einen Index
  • Schreiben von Daten über einen Index
  • Und sogar Löschen von Daten über einen Index.

Es ist überhaupt nicht notwendig, dass die Daten innen in Form einer Liste gespeichert werden. Oder dass der Index zwangsläufig eine Zahl sein muss. Zum Beispiel ist die Klasse dictionary (Wörterbuch) genau so implementiert.

Erstellen wir eine SuperList

Erinnerst du dich an die Klasse list? Man kann ihr Elemente zuweisen, aber nur mit den Indexen, die bereits existieren. Lass uns eine eigene Klasse erstellen, nennen wir sie SuperList, deren Elemente mit jedem Index zugänglich sind:

  • Wenn der Index < 0 ist, fügen wir das Element am Anfang ein
  • Wenn der Index >= len ist, fügen wir das Element am Ende hinzu
  • In allen anderen Fällen geben wir einfach das Element zurück

Beispiel:


class SuperList(list):
    def __init__(self, value):
        super().__init__(value)
        
    def __setitem__(self, index, value):
        if index >= len(self):
            super().append(value)
        elif index < 0:
            super().insert(0, value)
        else:
            super().__setitem__(index, value)
        
lst = SuperList([1, 2, 3])
lst[200] = 100
lst[-200] = 99
print(lst)  # [99, 1, 2, 3, 100]

So ist die Überladung von Indizes eine großartige Möglichkeit, und ich empfehle, sie in der Praxis zu nutzen. Das war's für heute.

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION