Lektionen des Moduls (3/4)
Spezielle Methoden (Dunder)
Spezialmethoden (auch Dunder-Methoden genannt, weil sie mit einem doppelten Unterstrich
beginnen und enden: __name__) sind die Schnittstellen, über die sich deine Objekte
in die Sprache integrieren lassen: Textdarstellung, Vergleich mit ==,
Unterstützung für len(), in, Operatoren usw.
Eine hast du bereits verwendet: __init__.
__str__ und __repr__
Sie steuern, was bei print() und im REPL angezeigt wird.
class Punto:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Punto({self.x}, {self.y})"
def __str__(self):
return f"({self.x}, {self.y})"
p = Punto(3, 4)
str(p) # '(3, 4)' — für Menschen
repr(p) # 'Punto(3, 4)' — für Debugger / Entwickler
print(p) # '(3, 4)'
p # Punto(3, 4) im REPL → repr
[p, p] # [Punto(3, 4), Punto(3, 4)] — in Containern immer reprWenn du nur __repr__ definierst, verwendet Python dieses auch als Fallback für
__str__.
__eq__: Neudefinition von ==
Standardmäßig vergleicht a == b die Identitäten der Objekte (is), nicht
deren Inhalt. Für einen strukturellen Vergleich definiere __eq__:
class Punto:
def __init__(self, x, y):
self.x, self.y = x, y
def __eq__(self, other):
if not isinstance(other, Punto):
return NotImplemented
return (self.x, self.y) == (other.x, other.y)
Punto(1, 2) == Punto(1, 2) # True
Punto(1, 2) == Punto(3, 4) # FalseDie Rückgabe von NotImplemented (ein spezielles Schlüsselwort, nicht False!), wenn die Typen
nicht vergleichbar sind, ist die korrekte Praxis: Python versucht es dann mit dem
__eq__ des anderen Operanden.
__len__: Unterstützung für len()
class Cesto:
def __init__(self):
self.frutti = []
def __len__(self):
return len(self.frutti)
c = Cesto()
c.frutti.append("mela")
len(c) # 1
bool(c) # True (len > 0)Durch das Definieren von __len__ erhältst du den Boolean-Wert umsonst: Ein Objekt
mit len() == 0 wird als Falsy gewertet.
Weitere nützliche Dunder-Methoden (Übersicht)
__add__(self, other)→ definiert+neu__lt__,__le__,__gt__,__ge__→ Vergleichsoperatoren__contains__(self, item)→ unterstütztitem in self__iter__+__next__→ macht das Objekt iterierbar__getitem__(self, key)→ unterstütztself[key]__hash__→ erforderlich, um ein Dictionary-Schlüssel / Set-Element zu sein
Probiere es aus
Definiere `Money` mit __init__(self, amount, currency) und __str__, das `f'{amount} {currency}'` zurückgibt. Erstelle `s = Money(42, 'EUR')` und evaluiere `str(s)`.
Hinweis anzeigen
f-String in __str__.
Lösung nach 3 Versuchen verfügbar
Wiederholungsübung
Definiere `Pair` mit __init__(self, a, b) and __eq__ basierend auf dem strukturellen Vergleich von (a, b). Evaluiere `Pair(1, 2) == Pair(1, 2)`.
Hinweis anzeigen
Vergleiche die Tupel (self.a, self.b) == (other.a, other.b).
Lösung nach 3 Versuchen verfügbar
Zusätzliche Herausforderung
Definiere eine Klasse `Book` mit einem Konstruktor, der `title` und `author` entgegennimmt. Definiere die Spezialmethode `__str__(self)` so, dass sie den String `"Title by Author"` zurückgibt (z.B. `'1984 by George Orwell'`). Instanziiere ein Buch und evaluiere `str(book)`.
Hinweis anzeigen
Verwende f"{self.title} by {self.author}" innerhalb von def __str__(self):.
Lösung nach 3 Versuchen verfügbar