Sovraccarico degli operatori
Fa parte della sezione Programmazione orientata agli oggetti del percorso Python di Coddy. Lezione 34 di 64.
L'overloading degli operatori consente alle tue classi di funzionare con gli operatori integrati di Python (+, -, *, ecc.) implementando metodi magici speciali.
Ecco un esempio di classe con sovraccarico degli operatori:
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})"Il metodo __add__ definisce cosa succede quando usi l’operatore +:
v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2 # Chiama v1.__add__(v2)
print(result)Il metodo __mul__ definisce cosa succede quando usi l’operatore *:
v1 = Vector(2, 3)
scaled = v1 * 3 # Chiama v1.__mul__(3)
print(scaled)Output:
Vector(7, 10)
Vector(6, 9)Aggiungi operatori di confronto:
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 - llama a v1.__eq__(v2)
print(v1 == v3) # FalsePunto chiave: l'overloading degli operatori usa metodi magici come __add__ (+), __sub__ (-), __mul__ (*), __eq__ (==) per definire il funzionamento degli operatori con i tuoi oggetti. Questo fa sì che le tue classi si comportino in modo naturale con gli operatori integrati di Python.
Sfida
MedioIn questa sfida implementerai una classe Money che rappresenta importi monetari con un robusto overload degli operatori. La tua implementazione verrà verificata a fondo con una suite di test completa.
money.py- Questo è l’unico file da modificare. Contiene la definizione della classe con commenti TODO che guidano la tua implementazione.driver.py- Contiene scenari di test approfonditi che convalidano la tua implementazione (non modificare).
Implementa la classe Money con le seguenti funzionalità:
- Un costruttore che accetta
amount(float) ecurrency(stringa) - Addizione (
+) di oggetti Money con la stessa valuta - Moltiplicazione (
*) per un numero per scalare l’importo - Confronto di uguaglianza (
==) tra oggetti Money - Rappresentazione come stringa nel formato “X.XX CUR”
Provalo tu
from money import Money
# Gestore dei casi di test
test_case = input()
def test_basic_functionality():
# Verifica l'inizializzazione e la rappresentazione come stringa
m1 = Money(10.0, "USD")
assert str(m1) == "10.00 USD", f"__str__ method failed, got {str(m1)}"
# Verifica l'addizione
m2 = Money(20.0, "USD")
m3 = m1 + m2
assert str(m3) == "30.00 USD", f"Addition failed, got {str(m3)}"
# Verifica l'addizione di valute diverse
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)}"
# Verifica la moltiplicazione
m6 = m1 * 3
assert str(m6) == "30.00 USD", f"Multiplication failed, got {str(m6)}"
# Verifica l'uguaglianza
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():
# Verifica il comportamento con un importo pari a zero
m1 = Money(0.0, "USD")
assert str(m1) == "0.00 USD", f"Zero amount string representation failed, got {str(m1)}"
# Verifica l'addizione con zero
m2 = Money(10.0, "USD")
m3 = m1 + m2
assert str(m3) == "10.00 USD", f"Addition with zero failed, got {str(m3)}"
# Verifica la moltiplicazione per zero
m4 = m2 * 0
assert str(m4) == "0.00 USD", f"Multiplication by zero failed, got {str(m4)}"
# Verifica l'uguaglianza con un importo pari a zero
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():
# Verifica il comportamento con un importo negativo
m1 = Money(-10.0, "USD")
assert str(m1) == "-10.00 USD", f"Negative amount string representation failed, got {str(m1)}"
# Verifica l'addizione con importi negativi
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)}"
# Verifica la moltiplicazione per uno scalare negativo
m6 = m2 * -2
assert str(m6) == "-40.00 USD", f"Multiplication by negative scalar failed, got {str(m6)}"
# Verifica l'uguaglianza con importi negativi
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():
# Verifica il comportamento con importi molto elevati
m1 = Money(1000000.0, "USD")
assert str(m1) == "1000000.00 USD", f"Large amount string representation failed, got {str(m1)}"
# Verifica l'addizione con importi elevati
m2 = Money(2000000.0, "USD")
m3 = m1 + m2
assert str(m3) == "3000000.00 USD", f"Addition with large amounts failed, got {str(m3)}"
# Verifica la moltiplicazione per uno scalare elevato
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():
# Verifica il comportamento con importi frazionari
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)}"
# Verifica l'addizione con importi frazionari
m3 = Money(0.75, "USD")
m4 = m1 + m3
assert str(m4) == "11.00 USD", f"Addition with fractional amounts failed, got {str(m4)}"
# Verifica la moltiplicazione per uno scalare frazionario
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:
# Queste operazioni dovrebbero funzionare senza errori
m1 = Money(10.0, "USD")
m2 = m1 * 2
m3 = m1 * 2.5
# Verifica l'uguaglianza con tipi diversi
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():
# Verifica la distinzione tra maiuscole e minuscole nei codici delle valute
m1 = Money(10.0, "USD")
m2 = Money(10.0, "usd")
# I codici delle valute dovrebbero distinguere tra maiuscole e minuscole
assert m1 != m2, "Currency comparison should be case-sensitive"
# L'aggiunta di valute con maiuscole e minuscole diverse deve fallire
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():
# Crea molti oggetti Money ed esegui operazioni
base = Money(1.0, "USD")
result = base
# Esegui 1000 addizioni
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)}"
# Esegui 10 moltiplicazioni
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!")
# Esegui il test appropriato in base all'input
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}")Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP
File esterniIntroduzione a OOPClassi vs. oggettiIl parametro selfMetodiAttributiMetodo costruttore (__init__)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa funzione super()Sovrascrittura dei metodiEreditarietà multiplaOrdine di risoluzione dei metodiRiepilogo - Gerarchia dei dipendenti7Metodi speciali
Introduzione ai metodi magiciSovraccarico degli operatoriMetodi magici dei contenitoriRiepilogo - Lista personalizzata10Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello ObserverModello Strategy2Decoratori
Introduzione ai decoratoriDecoratore di proprietàDecoratore di metodo staticoDecoratore di metodo di classe5Polimorfismo
Ripasso dell'override dei metodiDuck typingClassi e metodi astrattiProgettazione delle interfacceRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàMixinMetodi statici e di classeDecorator di classeContext manager11Pattern di progettazione - Parte 2
Pattern dei comandiPattern adattatorePattern decoratorePattern metodo templatePattern statoPattern composito3Proprietà delle classi
Variabili di istanza e di classeDecorator delle proprietàAttributi privatiRiepilogo - Gestore di conti bancari6Incapsulamento
Membri pubblici, protetti e privatiModificatori di accessoOccultamento delle informazioniDecorator delle proprietà: avanzatiRipasso - Sistema di registri degli studenti12Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e UtenteSistema di prestitoFunzionalità di ricercaInterfaccia amministratoreTest e integrazioneEsercitati da solo: Compilatore Python online