Menu
Coddy logo textTech

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)  # False

Point 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.

challenge icon

Défi

Moyen

Dans 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 :

  1. Un constructeur qui prend amount (float) et currency (string)
  2. L'addition (+) d'objets Money avec la même devise
  3. La multiplication (*) par un nombre pour mettre à l'échelle le montant
  4. La comparaison d'égalité (==) entre les objets Money
  5. 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}")
quiz iconTestez-vous

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