Operator-Überladung
Teil des Abschnitts Object Oriented Programming der Python-Journey von Coddy — Lektion 34 von 64.
Operatorüberladung ermöglicht es Ihren Klassen, mit Pythons integrierten Operatoren (+, -, *, etc.) zu arbeiten, indem sie spezielle magische Methoden implementieren.
Hier ist ein Beispiel für eine Klasse mit Operatorüberladung:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"Die Methode __add__ definiert, was passiert, wenn Sie den +-Operator verwenden:
v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2 # Ruft v1.__add__(v2) auf
print(result)Die __mul__-Methode definiert, was passiert, wenn Sie den *-Operator verwenden:
v1 = Vector(2, 3)
scaled = v1 * 3 # Ruft v1.__mul__(3) auf
print(scaled)Ausgabe:
Vector(7, 10)
Vector(6, 9)Vergleichsoperatoren hinzufügen:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(1, 1)
print(v1 == v2) # True - ruft v1.__eq__(v2) auf
print(v1 == v3) # FalseWichtiger Punkt: Operatorüberladung verwendet magische Methoden wie __add__ (+), __sub__ (-), __mul__ (*), __eq__ (==), um zu definieren, wie Operatoren mit Ihren Objekten funktionieren. Dadurch verhalten sich Ihre Klassen natürlich mit den integrierten Operatoren von Python.
Aufgabe
MittelIn dieser Herausforderung implementieren Sie eine Money-Klasse, die Geldbeträge mit robustem Operator-Overloading darstellt. Ihre Implementierung wird gründlich gegen eine umfassende Test-Suite geprüft.
money.py- Dies ist die einzige Datei, die Sie bearbeiten müssen. Sie enthält die Klassendefinition mit TODO-Kommentaren, die Sie durch die Implementierung führen.driver.py- Enthält umfangreiche Test-Szenarien, die Ihre Implementierung validieren (nicht ändern).
Implementieren Sie die Money-Klasse mit den folgenden Funktionen:
- Konstruktor, der
amount(float) undcurrency(string) entgegennimmt - Addition (
+) von Money-Objekten mit derselben Währung - Multiplikation (
*) mit einer Zahl, um den Betrag zu skalieren - Gleichheitsvergleich (
==) zwischen Money-Objekten - String-Repräsentation im Format "X.XX CUR"
Spickzettel
Operatorüberladung ermöglicht es Klassen, mit den integrierten Operatoren von Python zu arbeiten, indem spezielle Magic-Methods implementiert werden:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __str__(self):
return f"Vector({self.x}, {self.y})"Gängige Magic-Methods für die Operatorüberladung:
__add__für den+-Operator__sub__für den--Operator__mul__für den*-Operator__eq__für den==-Operator__str__für die String-Repräsentation
Anwendungsbeispiel:
v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2 # Ruft v1.__add__(v2) auf
scaled = v1 * 3 # Ruft v1.__mul__(3) auf
print(v1 == v2) # Ruft v1.__eq__(v2) aufProbier es selbst
from money import Money
# Testfall-Handler
test_case = input()
def test_basic_functionality():
# Teste Initialisierung und String-Repräsentation
m1 = Money(10.0, "USD")
assert str(m1) == "10.00 USD", f"__str__ method failed, got {str(m1)}"
# Teste Addition
m2 = Money(20.0, "USD")
m3 = m1 + m2
assert str(m3) == "30.00 USD", f"Addition failed, got {str(m3)}"
# Teste Addition verschiedener Währungen
m4 = Money(20.0, "EUR")
try:
m5 = m1 + m4
assert False, "Adding different currencies should raise an error"
except ValueError as e:
assert str(e) == "Cannot add different currencies", f"Wrong error message: {str(e)}"
# Teste Multiplikation
m6 = m1 * 3
assert str(m6) == "30.00 USD", f"Multiplication failed, got {str(m6)}"
# Teste Gleichheit
assert m1 == Money(10.0, "USD"), "Equality test failed"
assert m1 != m2, "Inequality test failed"
print("All basic functionality tests passed!")
def test_zero_values():
# Teste mit Nullbetrag
m1 = Money(0.0, "USD")
assert str(m1) == "0.00 USD", f"Zero amount string representation failed, got {str(m1)}"
# Teste Addition mit Null
m2 = Money(10.0, "USD")
m3 = m1 + m2
assert str(m3) == "10.00 USD", f"Addition with zero failed, got {str(m3)}"
# Teste Multiplikation mit Null
m4 = m2 * 0
assert str(m4) == "0.00 USD", f"Multiplication by zero failed, got {str(m4)}"
# Teste Gleichheit mit Nullbetrag
assert m1 == Money(0.0, "USD"), "Equality with zero amount failed"
assert m1 != m2, "Inequality with zero amount failed"
print("All zero value tests passed!")
def test_negative_values():
# Teste mit negativem Betrag
m1 = Money(-10.0, "USD")
assert str(m1) == "-10.00 USD", f"Negative amount string representation failed, got {str(m1)}"
# Teste Addition mit negativen Beträgen
m2 = Money(20.0, "USD")
m3 = m1 + m2
assert str(m3) == "10.00 USD", f"Addition with negative amount failed, got {str(m3)}"
m4 = Money(-5.0, "USD")
m5 = m1 + m4
assert str(m5) == "-15.00 USD", f"Addition of two negative amounts failed, got {str(m5)}"
# Teste Multiplikation mit negativem Skalar
m6 = m2 * -2
assert str(m6) == "-40.00 USD", f"Multiplication by negative scalar failed, got {str(m6)}"
# Teste Gleichheit mit negativen Beträgen
assert m1 == Money(-10.0, "USD"), "Equality with negative amount failed"
assert m1 != m2, "Inequality with negative amount failed"
print("All negative value tests passed!")
def test_large_values():
# Teste mit sehr großen Beträgen
m1 = Money(1000000.0, "USD")
assert str(m1) == "1000000.00 USD", f"Large amount string representation failed, got {str(m1)}"
# Teste Addition mit großen Beträgen
m2 = Money(2000000.0, "USD")
m3 = m1 + m2
assert str(m3) == "3000000.00 USD", f"Addition with large amounts failed, got {str(m3)}"
# Teste Multiplikation mit großem Skalar
m4 = m1 * 1000
assert str(m4) == "1000000000.00 USD", f"Multiplication with large scalar failed, got {str(m4)}"
print("All large value tests passed!")
def test_precision():
# Teste mit Dezimalbeträgen
m1 = Money(10.25, "USD")
assert str(m1) == "10.25 USD", f"Fractional amount string representation failed, got {str(m1)}"
m2 = Money(10.2, "USD")
assert str(m2) == "10.20 USD", f"Two decimal place formatting failed, got {str(m2)}"
# Teste Addition mit Dezimalbeträgen
m3 = Money(0.75, "USD")
m4 = m1 + m3
assert str(m4) == "11.00 USD", f"Addition with fractional amounts failed, got {str(m4)}"
# Teste Multiplikation mit Dezimalskalar
m5 = m1 * 0.5
assert str(m5) == "5.13 USD", f"Multiplication with fractional scalar failed, got {str(m5)}"
print("All precision tests passed!")
def test_type_validation():
try:
# Diese Operationen sollten ohne Fehler funktionieren
m1 = Money(10.0, "USD")
m2 = m1 * 2
m3 = m1 * 2.5
# Teste Gleichheit mit verschiedenen Typen
assert (m1 == "10.00 USD") == False, "Equality with string should return False"
assert (m1 == 10.0) == False, "Equality with number should return False"
print("All type validation tests passed!")
except Exception as e:
print(f"Type validation test failed: {e}")
def test_currency_case_sensitivity():
# Teste Groß-/Kleinschreibung der Währung
m1 = Money(10.0, "USD")
m2 = Money(10.0, "usd")
# Währungen sollten case-sensitive sein
assert m1 != m2, "Currency comparison should be case-sensitive"
# Das Addieren verschiedener Schreibweisen sollte fehlschlagen
try:
m3 = m1 + m2
assert False, "Adding different currency cases should raise an error"
except ValueError as e:
assert str(e) == "Cannot add different currencies", f"Wrong error message: {str(e)}"
print("All currency case sensitivity tests passed!")
def test_performance():
# Erstelle viele Money-Objekte und führe Operationen durch
base = Money(1.0, "USD")
result = base
# Führe 1000 Additionen durch
for i in range(1000):
result = result + Money(1.0, "USD")
assert str(result) == "1001.00 USD", f"Performance test addition failed, got {str(result)}"
# Führe 10 Multiplikationen durch
result = base
for i in range(10):
result = result * 2
assert str(result) == "1024.00 USD", f"Performance test multiplication failed, got {str(result)}"
print("All performance tests passed!")
# Führe den entsprechenden Test basierend auf der Eingabe aus
if test_case == "basic_test":
test_basic_functionality()
elif test_case == "zero_values":
test_zero_values()
elif test_case == "negative_values":
test_negative_values()
elif test_case == "large_values":
test_large_values()
elif test_case == "precision":
test_precision()
elif test_case == "type_validation":
test_type_validation()
elif test_case == "currency_case":
test_currency_case_sensitivity()
elif test_case == "performance":
test_performance()
else:
print(f"Unknown test case: {test_case}")Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Object Oriented Programming
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDer self-ParameterMethodenAttributeKonstruktor-Methode (__init__)Zusammenfassung – Einfacher Taschenrechner4Vererbung
Grundlagen der VererbungDie super()-FunktionMethoden überschreibenMehrfachvererbungMethod Resolution OrderZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden
Einführung in Magic MethodsOperator-ÜberladungMagic Methods für ContainerRückblick - Eigene Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterObserver-MusterStrategy-Muster13Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung2Dekoratoren
Einführung in DekoratorenProperty-DekoratorStatischer Methoden-DekoratorKlassenmethoden-Dekorator5Polymorphismus
Methoden-Überschreiben vertieftDuck TypingAbstrakte Klassen und MethodenInterface-DesignZusammenfassung – Formen-Rechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungMixinsStatische und KlassenmethodenKlassendekoratorenContext Manager3Klasseneigenschaften
Instanz- vs. KlassenvariablenProperty-DekoratorenPrivate AttributeZusammenfassung – Bankkonto-Manager6Kapselung
Public, Protected, Private MemberZugriffsmodifikatorenInformation HidingProperty-Decorators für FortgeschritteneZusammenfassung - Studentenverwaltungssystem12Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen