Saltar al contenido principal
eLearner.app
Módulo 7 · Lección 3 de 427/36 en el curso~12 min
Lecciones del módulo (3/4)

Métodos especiales (dunder)

Los métodos especiales (llamados dunder methods porque comienzan y terminan con un doble guion bajo: __name__) son los ganchos (hooks) que permiten a tus objetos integrarse con el lenguaje: representación de texto, comparación con ==, soporte para len(), in, operadores, etc.

Ya has utilizado uno: __init__.

__str__ y __repr__

Controlan lo que aparece al usar print() y en el REPL.

Python
class Punto:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Punto({self.x}, {self.y})"

    def __str__(self):
        return f"({self.x}, {self.y})"

p = Punto(3, 4)
str(p)        # '(3, 4)'        — para humanos
repr(p)       # 'Punto(3, 4)'   — para depurador / dev
print(p)      # '(3, 4)'
p             # Punto(3, 4)     en el REPL → repr
[p, p]        # [Punto(3, 4), Punto(3, 4)]   — siempre repr en los contenedores

Si defines solo __repr__, Python también lo usa como alternativa para __str__.

__eq__: redefinir ==

Por defecto, a == b compara los identificadores de los objetos (is), no su contenido. Para la comparación estructural, define __eq__:

Python
class Punto:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __eq__(self, other):
        if not isinstance(other, Punto):
            return NotImplemented
        return (self.x, self.y) == (other.x, other.y)

Punto(1, 2) == Punto(1, 2)    # True
Punto(1, 2) == Punto(3, 4)    # False

Devolver NotImplemented (¡una palabra clave especial, no False!) cuando los tipos no son comparables es la práctica correcta: Python intentará entonces con el __eq__ del otro operando.

__len__: soporte para len()

Python
class Cesto:
    def __init__(self):
        self.frutti = []

    def __len__(self):
        return len(self.frutti)

c = Cesto()
c.frutti.append("mela")
len(c)        # 1
bool(c)       # True (len > 0)

Al definir __len__, también obtienes el booleano gratis: un objeto con len() == 0 se vuelve falso (falsy).

Otros dunders útiles (resumen)

  • __add__(self, other) → redefine +
  • __lt__, __le__, __gt__, __ge__ → operadores de comparación
  • __contains__(self, item) → soporta item in self
  • __iter__ + __next__ → hace que el objeto sea iterable
  • __getitem__(self, key) → soporta self[key]
  • __hash__ → necesario para ser clave de diccionario / elemento de conjunto

Pruébalo tú

Ejercicio#python.m7.l3.e1
Intentos: 0Cargando...

Define `Money` con __init__(self, amount, currency) y __str__ que devuelva `f'{amount} {currency}'`. Crea `s = Money(42, 'EUR')` y evalúa `str(s)`.

Cargando editor...
Mostrar pista

f-string en __str__.

Solución disponible después de 3 intentos

Ejercicio de repaso

Ejercicio#python.m7.l3.e2
Intentos: 0Cargando...

Define `Pair` con __init__(self, a, b) y __eq__ basado en la comparación estructural de (a, b). Evalúa `Pair(1, 2) == Pair(1, 2)`.

Cargando editor...
Mostrar pista

Compara las tuplas (self.a, self.b) == (other.a, other.b).

Solución disponible después de 3 intentos

Desafío adicional

Ejercicio#python.m7.l3.e3
Intentos: 0Cargando...

Define una clase `Book` con un constructor que tome `title` y `author`. Define el método especial `__str__(self)` para que devuelva la cadena `"Title by Author"` (ej. `'1984 by George Orwell'`). Instancia un libro y evalúa `str(book)`.

Cargando editor...
Mostrar pista

Usa f"{self.title} by {self.author}" dentro de def __str__(self):.

Solución disponible después de 3 intentos