6.1 Métodos mágicos
La sobrecarga de operadores en Python te permite definir o cambiar el comportamiento
de los operadores incorporados (por ejemplo, +
, -
, *
, /
) para tus clases personalizadas.
Esto se hace usando métodos especiales, también conocidos como
métodos mágicos.
Por ejemplo, en tu clase puedes sobrecargar los operadores de comparación:
Operador | Método sin subrayado | Firma del método |
---|---|---|
== | eq() |
__eq__(self, other) |
!= | ne() |
__ne__(self, other) |
< | lt() |
__lt__(self, other) |
<= | le() |
__le__(self, other) |
> | gt() |
__gt__(self, other) |
>= | ge() |
__ge__(self, other) |
Supongamos que has creado tu clase y quieres que los objetos de tu clase
se comparen de la forma que tú decidas. Solo necesitas implementar en
tu clase el método «__eq__»
, y Python lo llamará cada
vez que los objetos de tu clase se comparen en el código.
Ejemplo:
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
# Uso
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2) # Mostrará: True
print(v1 == v3) # Mostrará: False
Cada vez que comparas dos de tus objetos, Python verifica si tienen
implementada la
función «__eq__»
. Si es así, la llama. Si no, simplemente compara las referencias a los objetos.
De hecho, en el ejemplo anterior está escrito (aunque hay que agregar la verificación de si el método existe):
# Uso
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2)) # Mostrará: True
print(v1.__eq__(v3)) # Mostrará: False
6.2 Lista de todos los operadores
En total, hay 6 grupos de operadores disponibles para sobrecarga.
Operadores aritméticos:
Operador | Método sin subrayado | Firma del método |
---|---|---|
+ | add |
__add__(self, other) |
- | sub |
__sub__(self, other) |
* | mul |
__mul__(self, other) |
/ | truediv |
__truediv__(self, other) |
// | floordiv |
__floordiv__(self, other) |
% | mod |
__mod__(self, other) |
** | pow |
__pow__(self, other) |
Operadores de comparación:
Operador | Método sin subrayado | Firma del método |
---|---|---|
== | eq |
__eq__(self, other) |
!= | ne |
__ne__(self, other) |
< | lt |
__lt__(self, other) |
<= | le |
__le__(self, other) |
> | gt |
__gt__(self, other) |
>= | ge |
__ge__(self, other) |
Operadores lógicos:
Operador | Método sin subrayado | Firma del método |
---|---|---|
& | and |
__and__(self, other) |
| | or |
__or__(self, other) |
^ | xor |
__xor__(self, other) |
~ | invert |
__invert__(self) |
Operadores de indexación y cortes:
Operador | Método |
---|---|
obj[key] | __getitem__(self, key) |
obj[key] = value | __setitem__(self, key, value) |
del obj[key] | __delitem__(self, key) |
Operadores unarios:
Operador | Método |
---|---|
- | __neg__(self) |
+ | __pos__(self) |
abs() | __abs__(self) |
~ | __invert__(self) |
Operadores de asignación:
Operador | Método |
---|---|
+= | __iadd__(self, other) |
-= | __isub__(self, other) |
*= | __imul__(self, other) |
/= | __itruediv__(self, other) |
//= | __ifloordiv__(self, other) |
%= | __imod__(self, other) |
**= | __ipow__(self, other) |
Tal vez por eso, Python es tan lento: cada vez que ejecuta un operador, busca una función análoga en la clase y todos sus padres. Pero esto permite escribir el código más compacto del mundo :)
6.3 Operador de indexación
Que puedas comparar objetos o restar conjuntos es, de alguna manera, obvio. Y tú mismo adivinas esto si escribes una clase que implica operaciones lógicas o matemáticas sobre ella.
Quiero discutir con ustedes un ejemplo interesante: el operador de indexación. Vamos a empezar con el ejemplo de código:
class CustomList:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
def __delitem__(self, index):
del self.data[index]
def __repr__(self):
return repr(self.data)
# Uso
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1]) # Mostrará: 2
c_list[1] = 10
print(c_list) # Mostrará: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list) # Mostrará: [1, 3, 4, 5]
Aquí vemos un ejemplo de tres operaciones:
Lectura de datos por índice
Escritura de datos por índice
E incluso eliminación de datos por índice.
Y no es necesario que los datos se almacenarán dentro como
una lista. O que el índice debe ser un número. Por ejemplo, la clase
dictionary
(diccionario) está implementada de esta manera.
Creando SuperList
¿Recuerdas la clase list
? Puedes asignarle elementos, pero solo con aquellos
índices que ya existen. Vamos a crear nuestra propia clase, la llamaremos
SuperList
, a cuyos elementos se puede acceder con cualquier
índice:
Si el índice < 0, insertaremos el elemento al inicio
Si el índice >= len, agregaremos el elemento al final
En otros casos simplemente devolveremos el elemento
Ejemplo:
class SuperList(list):
def __init__(self, value):
super().__init__(value)
def __setitem__(self, index, value):
if index >= len(self):
super().append(value)
elif index < 0:
super().insert(0, value)
else:
super().__setitem__(index, value)
lst = SuperList([1, 2, 3])
lst[200] = 100
lst[-200] = 99
print(lst) # [99, 1, 2, 3, 100]
Así que la sobrecarga de índices es una gran oportunidad, y te recomiendo usarla en la práctica. Eso es todo por hoy.
GO TO FULL VERSION