Aprende Python · lección gratuita
Los métodos especiales (también llamados dunder, por double underscore, es decir doble guion bajo) son métodos con nombres como __str__ o __len__ que Python invoca automáticamente en respuesta a operaciones del lenguaje. Tú no los llamas con objeto.__str__(); en su lugar usas print(objeto), len(objeto) o a == b, y Python se encarga de invocar el dunder correcto por debajo. Definirlos en tus clases hace que tus objetos se integren con la sintaxis natural de Python.
__str__(self) define el texto "amigable" que devuelve str(obj) y que usa print().__repr__(self) define la representación "técnica" que devuelve repr(obj) y que se ve en la consola interactiva.__len__(self) permite que len(obj) funcione sobre tus objetos; debe devolver un entero >= 0.__eq__(self, otro) define el comportamiento del operador == entre dos objetos.print(obj) usa __str__, len(obj) usa __len__.__repr__, print() lo usará como respaldo cuando falte __str__.Cuando escribes print(objeto), Python no imprime la dirección de memoria si tú le das una alternativa: busca un método __str__ en la clase del objeto y usa el texto que retorne. De forma parecida, len(objeto) busca __len__, y a == b busca __eq__. Estos "ganchos" permiten que tus clases se comporten como los tipos integrados (list, str, etc.). Por eso len([1, 2, 3]) funciona: las listas implementan __len__.
La diferencia entre __str__ y __repr__ es de propósito: __str__ está pensado para el usuario final (legible, bonito), mientras que __repr__ está pensado para el desarrollador (preciso, idealmente reconstruible). print() y str() prefieren __str__; la consola interactiva y repr() usan __repr__. Si solo defines uno, define __repr__, porque Python lo usa como respaldo de __str__.
class Punto:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Punto({self.x}, {self.y})"
def __eq__(self, otro):
return self.x == otro.x and self.y == otro.y
p = Punto(1, 2)
print(p) # Python llama a __str__ -> Punto(1, 2)
print(p == Punto(1, 2)) # Python llama a __eq__ -> True
# 1) __str__ controla lo que muestra print()
class Producto:
def __init__(self, nombre, precio):
self.nombre = nombre
self.precio = precio
def __str__(self):
return f"{self.nombre}: ${self.precio}"
print(Producto("Café", 12)) # Café: $12
# 2) __len__ hace que len() funcione sobre tu objeto
class Carrito:
def __init__(self):
self.items = ["pan", "leche", "huevos"]
def __len__(self):
return len(self.items)
print(len(Carrito())) # 3
# 3) __eq__ define el operador ==
class Color:
def __init__(self, hex):
self.hex = hex
def __eq__(self, otro):
return self.hex == otro.hex
print(Color("#fff") == Color("#fff")) # True
print(Color("#fff") == Color("#000")) # False
# 4) __repr__ se usa como respaldo de print() si no hay __str__
class Etiqueta:
def __init__(self, texto):
self.texto = texto
def __repr__(self):
return f"Etiqueta('{self.texto}')"
print(Etiqueta("oferta")) # Etiqueta('oferta')
💡 Define siempre__repr__en tus clases. Es el respaldo de__str__y te ahorra horas de depuración al mostrar objetos claros en la consola y en los mensajes de error.
| Método | Se activa con | Debe devolver |
|---|---|---|
__str__(self) | print(obj), str(obj) | un str legible |
__repr__(self) | repr(obj), consola, respaldo de str | un str técnico |
__len__(self) | len(obj) | un int >= 0 |
__eq__(self, otro) | obj == otro | un bool |
__init__(self, ...) | Clase(...) | nada (None) |
---