Sobrecarga del operador de Python

Puede cambiar el significado de un operador en Python según los operandos utilizados. En este tutorial, aprenderá a utilizar la sobrecarga de operadores en la programación orientada a objetos de Python.

Sobrecarga del operador de Python

Los operadores de Python funcionan para clases integradas. Pero el mismo operador se comporta de manera diferente con diferentes tipos. Por ejemplo, el +operador realizará la suma aritmética de dos números, fusionará dos listas o concatenará dos cadenas.

Esta característica en Python que permite que el mismo operador tenga un significado diferente según el contexto se llama sobrecarga de operador.

Entonces, ¿qué sucede cuando los usamos con objetos de una clase definida por el usuario? Consideremos la siguiente clase, que intenta simular un punto en un sistema de coordenadas 2-D.

 class Point: def __init__(self, x=0, y=0): self.x = x self.y = y p1 = Point(1, 2) p2 = Point(2, 3) print(p1+p2)

Salida

 Traceback (última llamada más reciente): Archivo "", línea 9, en letra impresa (p1 + p2) TypeError: tipo (s) de operando no admitido para +: 'Point' y 'Point'

Aquí, podemos ver que TypeErrorse generó a, ya que Python no sabía cómo sumar dos Pointobjetos.

Sin embargo, podemos lograr esta tarea en Python mediante la sobrecarga de operadores. Pero primero, tengamos una noción sobre las funciones especiales.

Funciones especiales de Python

Las funciones de clase que comienzan con doble subrayado __se denominan funciones especiales en Python.

Estas funciones no son las funciones típicas que definimos para una clase. La __init__()función que definimos anteriormente es una de ellas. Se llama cada vez que creamos un nuevo objeto de esa clase.

Hay muchas otras funciones especiales en Python. Visite Funciones especiales de Python para obtener más información sobre ellas.

Usando funciones especiales, podemos hacer que nuestra clase sea compatible con las funciones integradas.

 >>> p1 = Point(2,3) >>> print(p1) 

Supongamos que queremos que la print()función imprima las coordenadas del Pointobjeto en lugar de lo que obtuvimos. Podemos definir un __str__()método en nuestra clase que controle cómo se imprime el objeto. Veamos cómo podemos lograr esto:

 class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x,self.y)

Ahora intentemos la print()función nuevamente.

 class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0), (1))".format(self.x, self.y) p1 = Point(2, 3) print(p1)

Salida

 (2, 3)

Eso es mejor. Resulta que este mismo método se invoca cuando usamos la función incorporada str()o format().

 >>> str(p1) '(2,3)' >>> format(p1) '(2,3)'

Entonces, cuando usa str(p1)o format(p1), Python llama internamente al p1.__str__()método. De ahí el nombre, funciones especiales.

Ahora volvamos a la sobrecarga del operador.

Sobrecarga del operador +

Para sobrecargar el +operador, necesitaremos implementar la __add__()función en la clase. Con un gran poder viene una gran responsabilidad. Podemos hacer lo que queramos, dentro de esta función. Pero es más sensato devolver un Pointobjeto de la suma de coordenadas.

 class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Point(x, y)

Ahora intentemos la operación de suma nuevamente:

 class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Point(x, y) p1 = Point(1, 2) p2 = Point(2, 3) print(p1+p2)

Salida

 (3,5)

Lo que realmente sucede es que, cuando usas p1 + p2, Python llama, p1.__add__(p2)que a su vez es Point.__add__(p1,p2). Después de esto, la operación de adición se lleva a cabo de la forma que especificamos.

Del mismo modo, también podemos sobrecargar a otros operadores. La función especial que debemos implementar se tabula a continuación.

Operador Expresión Internamente
Adición p1 + p2 p1.__add__(p2)
Sustracción p1 - p2 p1.__sub__(p2)
Multiplicación p1 * p2 p1.__mul__(p2)
Poder p1 ** p2 p1.__pow__(p2)
División p1 / p2 p1.__truediv__(p2)
División de piso p1 // p2 p1.__floordiv__(p2)
Resto (módulo) p1 % p2 p1.__mod__(p2)
Desplazamiento a la izquierda bit a bit p1 << p2 p1.__lshift__(p2)
Desplazamiento a la derecha bit a bit p1>> p2 p1.__rshift__(p2)
Y bit a bit p1 & p2 p1.__and__(p2)
O bit a bit p1 | p2 p1.__or__(p2)
XOR bit a bit p1 p2 p1.__xor__(p2)
Bit a bit NO ~p1 p1.__invert__()

Operadores de comparación de sobrecarga

Python no limita la sobrecarga de operadores solo a operadores aritméticos. También podemos sobrecargar los operadores de comparación.

Supongamos que quisiéramos implementar el símbolo menor que <en nuestra Pointclase.

Comparemos la magnitud de estos puntos desde el origen y devolvamos el resultado para este propósito. Se puede implementar de la siguiente manera.

 # overloading the less than operator class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __lt__(self, other): self_mag = (self.x ** 2) + (self.y ** 2) other_mag = (other.x ** 2) + (other.y ** 2) return self_mag < other_mag p1 = Point(1,1) p2 = Point(-2,-3) p3 = Point(1,-1) # use less than print(p1 

Output

 True False False

Similarly, the special functions that we need to implement, to overload other comparison operators are tabulated below.

Operator Expression Internally
Less than p1 < p2 p1.__lt__(p2)
Less than or equal to p1 <= p2 p1.__le__(p2)
Equal to p1 == p2 p1.__eq__(p2)
Not equal to p1 != p2 p1.__ne__(p2)
Greater than p1> p2 p1.__gt__(p2)
Greater than or equal to p1>= p2 p1.__ge__(p2)

Articulos interesantes...