Surcharge d'opérateurs
Fait partie de la section Object Oriented Programming du Journey Python de Coddy — leçon 34 sur 64.
La surcharge d'opérateurs permet à vos classes de fonctionner avec les opérateurs intégrés de Python (+, -, *, etc.) en implémentant des méthodes magiques spéciales.
Voici un exemple d'une classe avec surcharge d'opérateurs :
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})"La méthode __add__ définit ce qui se passe lorsque vous utilisez l'opérateur + :
v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2 # Appelle v1.__add__(v2)
print(result)La méthode __mul__ définit ce qui se passe lorsque vous utilisez l'opérateur * :
v1 = Vector(2, 3)
scaled = v1 * 3 # Appelle v1.__mul__(3)
print(scaled)Sortie :
Vector(7, 10)
Vector(6, 9)Ajoutez des opérateurs de comparaison :
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 - appelle v1.__eq__(v2)
print(v1 == v3) # FalsePoint clé : La surcharge d'opérateurs utilise des méthodes magiques comme __add__ (+), __sub__ (-), __mul__ (*), __eq__ (==) pour définir comment les opérateurs fonctionnent avec vos objets. Cela permet à vos classes de se comporter naturellement avec les opérateurs intégrés de Python.
Défi
MoyenDans ce défi, vous allez implémenter une classe Money qui représente des montants monétaires avec une surcharge d'opérateurs robuste. Votre implémentation sera testée de manière approfondie par une suite de tests complète.
money.py- C'est le seul fichier que vous devez modifier. Il contient la définition de la classe avec des commentaires TODO pour guider votre implémentation.driver.py- Contient des scénarios de test étendus qui valident votre implémentation (ne pas modifier).
Implémentez la classe Money avec les fonctionnalités suivantes :
- Un constructeur qui prend
amount(float) etcurrency(string) - L'addition (
+) d'objets Money avec la même devise - La multiplication (
*) par un nombre pour mettre à l'échelle le montant - La comparaison d'égalité (
==) entre les objets Money - Une représentation sous forme de chaîne de caractères au format "X.XX CUR"
Aide-mémoire
La surcharge d'opérateurs permet aux classes de fonctionner avec les opérateurs intégrés de Python en implémentant des méthodes magiques spéciales :
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})"Méthodes magiques courantes pour la surcharge d'opérateurs :
__add__pour l'opérateur+__sub__pour l'opérateur-__mul__pour l'opérateur*__eq__pour l'opérateur==__str__pour la représentation sous forme de chaîne
Exemple d'utilisation :
v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2 # Appelle v1.__add__(v2)
scaled = v1 * 3 # Appelle v1.__mul__(3)
print(v1 == v2) # Appelle v1.__eq__(v2)Essayez vous-même
from money import Money
# Gestionnaire de cas de test
test_case = input()
def test_basic_functionality():
# Test de l'initialisation et de la représentation sous forme de chaîne
m1 = Money(10.0, "USD")
assert str(m1) == "10.00 USD", f"__str__ method failed, got {str(m1)}"
# Test de l'addition
m2 = Money(20.0, "USD")
m3 = m1 + m2
assert str(m3) == "30.00 USD", f"Addition failed, got {str(m3)}"
# Test de l'addition de devises différentes
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)}"
# Test de la multiplication
m6 = m1 * 3
assert str(m6) == "30.00 USD", f"Multiplication failed, got {str(m6)}"
# Test d'égalité
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():
# Test avec un montant nul
m1 = Money(0.0, "USD")
assert str(m1) == "0.00 USD", f"Zero amount string representation failed, got {str(m1)}"
# Test de l'addition avec zéro
m2 = Money(10.0, "USD")
m3 = m1 + m2
assert str(m3) == "10.00 USD", f"Addition with zero failed, got {str(m3)}"
# Test de la multiplication par zéro
m4 = m2 * 0
assert str(m4) == "0.00 USD", f"Multiplication by zero failed, got {str(m4)}"
# Test d'égalité avec un montant nul
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():
# Test avec un montant négatif
m1 = Money(-10.0, "USD")
assert str(m1) == "-10.00 USD", f"Negative amount string representation failed, got {str(m1)}"
# Test de l'addition avec des montants négatifs
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)}"
# Test de la multiplication par un scalaire négatif
m6 = m2 * -2
assert str(m6) == "-40.00 USD", f"Multiplication by negative scalar failed, got {str(m6)}"
# Test d'égalité avec des montants négatifs
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():
# Test avec de très grands montants
m1 = Money(1000000.0, "USD")
assert str(m1) == "1000000.00 USD", f"Large amount string representation failed, got {str(m1)}"
# Test de l'addition avec de grands montants
m2 = Money(2000000.0, "USD")
m3 = m1 + m2
assert str(m3) == "3000000.00 USD", f"Addition with large amounts failed, got {str(m3)}"
# Test de la multiplication avec un grand scalaire
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():
# Test avec des montants fractionnaires
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)}"
# Test de l'addition avec des montants fractionnaires
m3 = Money(0.75, "USD")
m4 = m1 + m3
assert str(m4) == "11.00 USD", f"Addition with fractional amounts failed, got {str(m4)}"
# Test de la multiplication avec un scalaire fractionnaire
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:
# Ces opérations devraient fonctionner sans erreurs
m1 = Money(10.0, "USD")
m2 = m1 * 2
m3 = m1 * 2.5
# Test d'égalité avec différents types
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():
# Test de la sensibilité à la casse de la devise
m1 = Money(10.0, "USD")
m2 = Money(10.0, "usd")
# Les devises doivent être sensibles à la casse
assert m1 != m2, "Currency comparison should be case-sensitive"
# L'ajout de casses différentes devrait échouer
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():
# Créer de nombreux objets Money et effectuer des opérations
base = Money(1.0, "USD")
result = base
# Effectuer 1000 additions
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)}"
# Effectuer 10 multiplications
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!")
# Exécuter le test approprié en fonction de l'entrée
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}")Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Object Oriented Programming
1Les fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe paramètre selfMéthodesAttributsMéthode constructeur (__init__)Récapitulatif - Calculatrice simple4Héritage
Héritage de baseLa fonction super()Redéfinition de méthodeHéritage multipleOrdre de résolution des méthodesRécapitulatif - Hiérarchie des employés7Méthodes spéciales
Introduction aux méthodes magiquesSurcharge d'opérateursMéthodes magiques de conteneurRécapitulatif - Liste personnalisée10Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FactoryPatron ObserverPatron Strategy2Décorateurs
Introduction aux décorateursDécorateur de propriétéDécorateur de méthode statiqueDécorateur de méthode de classe5Polymorphisme
Retour sur la redéfinition de méthodeDuck TypingClasses et méthodes abstraitesConception d'interfacesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageMixinsMéthodes statiques et de classeDécorateurs de classeGestionnaires de contexte11Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Méthode TemplatePatron ÉtatPatron Composite3Propriétés de classe
Variables d'instance vs variables de classeDécorateurs de propriétéAttributs privésRécapitulatif - Gestionnaire de compte bancaire