Los ✨métodos mágicos✨ de Python (que de mágicos no tienen nada 😅)
¿De dónde viene eso de __len__, __getitem__, __add__?
En el mundo de Python, los métodos mágicos o "dunder" (abreviación de "double underscore") son los pilares de la funcionalidad avanzada en las clases. A pesar de su nombre, no hay magia; son simplemente los métodos que el intérprete de Python invoca automáticamente cuando realizamos operaciones comunes, como sumar dos objetos, iterar sobre ellos, o incluso comprobar si un elemento está presente en una colección. Son clave en lo que se conoce como el Python Data Model1.
¿Qué hace especiales a los métodos mágicos?
Los métodos mágicos nos permiten definir cómo los objetos creados con nuestras clases deben comportarse ante operaciones y funciones comunes. Aunque rara vez invocamos estos métodos directamente, Python lo hace por nosotros. Por ejemplo:
Cuando usamos len(objeto), en realidad se está invocando objeto.__len__().
Si sumamos dos objetos, como a + b, Python realmente llama a a.__add__(b) (Nota: Acordate de este que al final lo vamos a retomar 😉).
Esto no solo hace que nuestros objetos sean más naturales de usar, sino que también nos permite crear comportamientos personalizados para operaciones específicas.
Ejemplos cotidianos: el poder de len y getitem
Los métodos mágicos como __len__ y __getitem__ son dos de los más conocidos, ya que permiten a nuestras clases comportarse como secuencias.
1. El método __len__: Este método es invocado por la función len(). Permite que nuestra clase pueda devolver su tamaño cuando usemos len(objeto)
2. El método __getitem__: Este método permite que nuestra clase sea "indexable". Al implementarlo, podemos acceder a sus elementos con la sintaxis de corchetes, como si fuera una lista o una tupla.
Veamos cómo estos métodos pueden aplicarse en un ejemplo sencillo con una clase que representa un grupo de carpinchos:
class CarpinchoGrupo:
def __init__(self, carpinchos):
self._carpinchos = carpinchos
def __len__(self):
contador = 0
for carpincho in self._carpinchos:
contador += 1
return contador
def __getitem__(self, index):
return self._carpinchos[index]
# Crear un grupo de carpinchos
grupo = CarpinchoGrupo(['Capy1', 'Capy2', 'Capy3'])
print(len(grupo)) # 3
print(grupo[0]) # 'Capy1'
En este ejemplo:
__len__: Permite que la función len() funcione con la instancia de CarpinchoGrupo, devolviendo el número de carpinchos en el grupo. Es importante notar que la maner más eficiente de implementar este método hubiera sido la siguiente:
class CarpinchoGrupo: def __init__(self, carpinchos): self._carpinchos = carpinchos def __len__(self): return len(self._carpinchos)
Sin embargo me parece importante mostrar que uno podría implementar el método de la manera que considere más conveniente.
__getitem__: Permite que la clase sea indexada, como si fuera una lista. Así, podemos acceder a los carpinchos individuales con grupo[0].
Expandiendo el uso de métodos mágicos
Python ofrece una amplia variedad de métodos mágicos que pueden dotar a nuestras clases de comportamientos más complejos2. Algunos ejemplos adicionales son:
__iter__: Para hacer que nuestros objetos sean iterables.
__contains__: Nos permite usar el operador in para verificar si un elemento está dentro del objeto.
__call__: Permite que una instancia de una clase se comporte como una función.
Si bien su implementación no siempre es necesaria, entender cómo funcionan y cómo utilizarlos puede elevar el nivel de nuestras clases, permitiendo un diseño más intuitivo y funcional.
¿Por qué son importantes?
Los métodos mágicos hacen que nuestras clases se sientan "naturales" dentro del ecosistema de Python. En lugar de crear clases que requieren métodos especializados para acceder o modificar datos, podemos hacer que se comporten como tipos nativos del lenguaje, simplificando tanto su uso como su comprensión.
¿Y qué me ibas a decir sobre a + b?
Para reforzar la idea de que cada implementación del método dunder podría tener un comportamiento diferente, esto pasa en Python algunas veces en función del tipo de dato que utilicemos. En el caso del operador “+”, si lo que tenemos a derecha e izquierda son números los va a sumar (2 + 3 devolverá 5), sin embargo si lo que tenemos son listas los va a concatenar ( [2] + [3] devolverá [2, 3]). Veamos un ejemplo con carpinchos que siempre hacen que se entiendan mejor las cosas:
class CarpinchoGrupo:
def __init__(self, carpinchos):
self._carpinchos = carpinchos
def __add__(self, otro_grupo):
# Combina los carpinchos de ambos grupos en una nueva lista
return CarpinchoGrupo(self._carpinchos + otro_grupo._carpinchos)
def __repr__(self):
return f"CarpinchoGrupo({self._carpinchos})"
# Crear dos grupos de carpinchos
grupo1 = CarpinchoGrupo(['Capy1', 'Capy2'])
grupo2 = CarpinchoGrupo(['Capy3', 'Capy4'])
# Concatenar los dos grupos usando el operador "+"
grupo_combinado = grupo1 + grupo2
# Mostrar el grupo combinado
print(grupo_combinado) # CarpinchoGrupo(['Capy1', 'Capy2', 'Capy3', 'Capy4'])
En este caso el comportamiento del operador “+” para un objeto CarpinchoGrupo es similar al que tiene Python con las listas, pero distinto al que tiene con los números.
Conclusión
Los métodos mágicos son una poderosa herramienta que nos proporciona Python para definir comportamientos personalizados en nuestras clases. Lejos de ser complicados, son simplemente métodos que Python llama automáticamente en segundo plano para realizar tareas cotidianas, como obtener la longitud de un objeto o iterar sobre él. La idea de este breve poste es que no te asustes si te encontras con esas palabras con muchos guiones bajos, sino que te familiriaces con esta poderosa herramienta que te va a ayudar a escribir código más limpio.
¿Te interesa seguir aprendiendo más sobre Python?
Si este contenido te resultó útil y te interesa leer contenido sobre programación principalmente en Python, ciencia de datos e inteligencia artificial? Seguime en en mis redes:
🐙 Github: https://github.com/GEJ1
📘 LinkedIn: Gustavo Juantorena
📹 YouTube: Gustavo Juantorena - Programación y Ciencia de Datos
Si te gustó el post, ¡Compartilo para que más personas puedan aprender!
https://docs.python.org/es/3/reference/datamodel.html
https://docs.python.org/es/3/reference/datamodel.html#special-method-names
La verdad es que no tenía ni idea de los métodos dunder y he conocido un poco más. Te sigo por aquí Gustavo y por Github, gracias