Menu
Coddy logo textTech

Sobrecarga de operadores

Parte de la sección Object Oriented Programming del Journey de Python de Coddy — lección 34 de 64.

La sobrecarga de operadores permite que sus clases trabajen con los operadores integrados de Python (+, -, *, etc.) mediante la implementación de métodos mágicos especiales.

Aquí hay un ejemplo de una clase con sobrecarga de operadores:

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})"

El método __add__ define qué sucede cuando usas el operador +:

v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2  # Llama a v1.__add__(v2)
print(result)

El método __mul__ define qué sucede cuando usas el operador *:

v1 = Vector(2, 3)
scaled = v1 * 3   # Llama a v1.__mul__(3)
print(scaled)

Salida:

Vector(7, 10)
Vector(6, 9)

Añade operadores de comparación:

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

Punto clave: La sobrecarga de operadores utiliza métodos mágicos como __add__ (+), __sub__ (-), __mul__ (*), __eq__ (==) para definir cómo funcionan los operadores con tus objetos. Esto hace que tus clases se comporten de forma natural con los operadores integrados de Python.

challenge icon

Desafío

Intermedio

En este desafío, implementarás una clase Money que representa cantidades monetarias con una robusta sobrecarga de operadores. Tu implementación será probada exhaustivamente con una suite de pruebas completa.

  • money.py - Este es el único archivo que necesitas editar. Contiene la definición de la clase con comentarios TODO que guían tu implementación.
  • driver.py - Contiene extensos escenarios de prueba que validan tu implementación (no lo modifiques).

Implementa la clase Money con las siguientes características:

  1. Constructor que recibe amount (float) y currency (string)
  2. Suma (+) de objetos Money con la misma moneda
  3. Multiplicación (*) por un número para escalar la cantidad
  4. Comparación de igualdad (==) entre objetos Money
  5. Representación de cadena en el formato “X.XX CUR”

Hoja de referencia

La sobrecarga de operadores permite que las clases trabajen con los operadores integrados de Python mediante la implementación de métodos mágicos especiales:

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étodos mágicos comunes para la sobrecarga de operadores:

  • __add__ para el operador +
  • __sub__ para el operador -
  • __mul__ para el operador *
  • __eq__ para el operador ==
  • __str__ para la representación de cadena

Ejemplo de uso:

v1 = Vector(2, 3)
v2 = Vector(5, 7)
result = v1 + v2  # Llama a v1.__add__(v2)
scaled = v1 * 3   # Llama a v1.__mul__(3)
print(v1 == v2)   # Llama a v1.__eq__(v2)

Pruébalo tú mismo

from money import Money

# Manejador de casos de prueba
test_case = input()

def test_basic_functionality():
    # Probar inicialización y representación de cadena
    m1 = Money(10.0, "USD")
    assert str(m1) == "10.00 USD", f"__str__ method failed, got {str(m1)}"
    
    # Probar suma
    m2 = Money(20.0, "USD")
    m3 = m1 + m2
    assert str(m3) == "30.00 USD", f"Addition failed, got {str(m3)}"
    
    # Probar suma de diferentes monedas
    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)}"
    
    # Probar multiplicación
    m6 = m1 * 3
    assert str(m6) == "30.00 USD", f"Multiplication failed, got {str(m6)}"
    
    # Probar igualdad
    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():
    # Probar con cantidad cero
    m1 = Money(0.0, "USD")
    assert str(m1) == "0.00 USD", f"Zero amount string representation failed, got {str(m1)}"
    
    # Probar suma con cero
    m2 = Money(10.0, "USD")
    m3 = m1 + m2
    assert str(m3) == "10.00 USD", f"Addition with zero failed, got {str(m3)}"
    
    # Probar multiplicación por cero
    m4 = m2 * 0
    assert str(m4) == "0.00 USD", f"Multiplication by zero failed, got {str(m4)}"
    
    # Probar igualdad con cantidad cero
    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():
    # Probar con cantidad negativa
    m1 = Money(-10.0, "USD")
    assert str(m1) == "-10.00 USD", f"Negative amount string representation failed, got {str(m1)}"
    
    # Probar suma con cantidades negativas
    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)}"
    
    # Probar multiplicación por escalar negativo
    m6 = m2 * -2
    assert str(m6) == "-40.00 USD", f"Multiplication by negative scalar failed, got {str(m6)}"
    
    # Probar igualdad con cantidades negativas
    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():
    # Probar con cantidades muy grandes
    m1 = Money(1000000.0, "USD")
    assert str(m1) == "1000000.00 USD", f"Large amount string representation failed, got {str(m1)}"
    
    # Probar suma con cantidades grandes
    m2 = Money(2000000.0, "USD")
    m3 = m1 + m2
    assert str(m3) == "3000000.00 USD", f"Addition with large amounts failed, got {str(m3)}"
    
    # Probar multiplicación con escalar grande
    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():
    # Probar con cantidades fraccionarias
    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)}"
    
    # Probar suma con cantidades fraccionarias
    m3 = Money(0.75, "USD")
    m4 = m1 + m3
    assert str(m4) == "11.00 USD", f"Addition with fractional amounts failed, got {str(m4)}"
    
    # Probar multiplicación con escalar fraccionario
    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:
        # Estas operaciones deberían funcionar sin errores
        m1 = Money(10.0, "USD")
        m2 = m1 * 2
        m3 = m1 * 2.5
        
        # Probar igualdad con diferentes tipos
        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():
    # Probar sensibilidad a mayúsculas en la moneda
    m1 = Money(10.0, "USD")
    m2 = Money(10.0, "usd")
    
    # Las monedas deben ser sensibles a mayúsculas
    assert m1 != m2, "Currency comparison should be case-sensitive"
    
    # Sumar diferentes casos debería fallar
    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():
    # Crear muchos objetos Money y realizar operaciones
    base = Money(1.0, "USD")
    result = base
    
    # Realizar 1000 sumas
    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)}"
    
    # Realizar 10 multiplicaciones
    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!")

# Ejecutar la prueba apropiada basada en la entrada
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 iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming