DMarlon Studio

Lección 10 · 10 de 20

Métodos especiales · Python

Haga que sus objetos se escriban, comparen, sumen y midan como los de Python con __repr__, __eq__, __lt__, __add__ y __len__.

Python · Métodos especiales en DMarlon Studio: el código del ejemplo y su salida en la terminal

Los métodos especiales (o *dunder*, por los dos guiones bajos) son los que Python llama por su cuenta cuando usa operadores y funciones integradas. Money guarda el importe en céntimos (cents), un entero, para no arrastrar errores de redondeo.

`__repr__` devuelve el texto que representa al objeto. Se usa en print() cuando no hay __str__ y, sobre todo, dentro de listas: por eso cart.prices sale como [19.99 EUR, 4.50 EUR, 120.00 EUR] y no como direcciones de memoria.

`__eq__` define ==: compara importe y moneda como una tupla. Sin él, dos Money(450) serían distintos porque son objetos diferentes. `__lt__` define <, y con eso basta para que sorted(), min() y max() sepan ordenar.

`__add__` define + y devuelve un Money nuevo. Gracias a él funciona sum(cart.prices, Money(0)): sum empieza en el segundo argumento (que debe ser un Money, no el 0 por defecto) y va sumando con +. Si las monedas no coinciden, lanza ValueError.

En Cart, `__len__` hace que len(cart) funcione. Hay muchos más: __getitem__ para cart[0], __contains__ para in, __bool__ para if cart:…

Código · main.py

class Money:    def __init__(self, cents, currency="EUR"):        self.cents = cents        self.currency = currency    def __repr__(self):               # how it prints, also inside lists        return f"{self.cents / 100:.2f} {self.currency}"    def __eq__(self, other):          # ==        return (self.cents, self.currency) == (other.cents, other.currency)    def __lt__(self, other):          # < (and so sorted, min, max)        return self.cents < other.cents    def __add__(self, other):         # +        if self.currency != other.currency:            raise ValueError("cannot add different currencies")        return Money(self.cents + other.cents, self.currency)class Cart:    def __init__(self, *prices):        self.prices = list(prices)    def __len__(self):                # len(cart)        return len(self.prices)cart = Cart(Money(1999), Money(450), Money(12000))print("Items:", len(cart), cart.prices)print("Total:", sum(cart.prices, Money(0)))print("Sorted:", sorted(cart.prices))print("Equal:", Money(450) == Money(450), "| less:", Money(450) < Money(1999))try:    Money(100) + Money(100, "USD")except ValueError as error:    print("Error:", error)

Salida · python3 main.py

Items: 3 [19.99 EUR, 4.50 EUR, 120.00 EUR]
Total: 144.49 EUR
Sorted: [4.50 EUR, 19.99 EUR, 120.00 EUR]
Equal: True | less: True
Error: cannot add different currencies

Para recordar

  • Python llama a los métodos especiales por usted: + llama a __add__.
  • __repr__ es la representación; procure que sea clara.
  • __eq__ define == y __lt__ basta para ordenar.
  • __len__ hace funcionar len().
  • Guardar el dinero en céntimos enteros evita errores de redondeo.

Ejercicio

Añada __mul__ a Money para que Money(1999) * 3 devuelva 59.97 EUR, y úselo para cobrar tres unidades del primer artículo.