Sobrecarga do operador Python

Você pode alterar o significado de um operador em Python, dependendo dos operandos usados. Neste tutorial, você aprenderá como usar a sobrecarga de operador na Programação Orientada a Objetos Python.

Sobrecarga do operador Python

Operadores Python funcionam para classes integradas. Mas o mesmo operador se comporta de maneira diferente com tipos diferentes. Por exemplo, o +operador executará adição aritmética em dois números, mesclará duas listas ou concatenará duas strings.

Esse recurso em Python que permite que o mesmo operador tenha significados diferentes de acordo com o contexto é chamado de sobrecarga de operador.

Então, o que acontece quando os usamos com objetos de uma classe definida pelo usuário? Vamos considerar a seguinte classe, que tenta simular um ponto no 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)

Resultado

 Traceback (última chamada mais recente): Arquivo "", linha 9, impresso (p1 + p2) TypeError: tipo (s) de operando não suportado (s) para +: 'Ponto' e 'Ponto'

Aqui, podemos ver que a TypeErrorfoi gerado, já que Python não sabia como adicionar dois Pointobjetos juntos.

No entanto, podemos realizar essa tarefa em Python por meio da sobrecarga do operador. Mas primeiro, vamos ter uma noção sobre funções especiais.

Funções especiais do Python

As funções de classe que começam com sublinhado duplo __são chamadas de funções especiais em Python.

Essas funções não são as funções típicas que definimos para uma classe. A __init__()função que definimos acima é uma delas. Ele é chamado toda vez que criamos um novo objeto dessa classe.

Existem inúmeras outras funções especiais em Python. Visite Python Special Functions para aprender mais sobre eles.

Usando funções especiais, podemos tornar nossa classe compatível com funções integradas.

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

Suponha que queremos que a print()função imprima as coordenadas do Pointobjeto em vez do que obtivemos. Podemos definir um __str__()método em nossa classe que controla como o objeto é impresso. Vejamos como podemos conseguir isso:

 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)

Agora vamos tentar a print()função novamente.

 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)

Resultado

 (2, 3)

Isso é melhor. Acontece que esse mesmo método é invocado quando usamos a função interna str()ou format().

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

Portanto, quando você usa str(p1)ou format(p1), o Python chama o p1.__str__()método internamente . Daí o nome funções especiais.

Agora vamos voltar à sobrecarga do operador.

Sobrecarregando o + Operador

Para sobrecarregar o +operador, precisaremos implementar a __add__()função na classe. Com grandes poderes vem grandes responsabilidades. Podemos fazer o que quisermos, dentro desta função. Mas é mais sensato retornar um Pointobjeto da soma das 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)

Agora vamos tentar a operação de adição novamente:

 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)

Resultado

 (3,5)

O que realmente acontece é que, quando você usa p1 + p2, Python chama p1.__add__(p2)que por sua vez é Point.__add__(p1,p2). Depois disso, a operação de adição é realizada da maneira que especificamos.

Da mesma forma, podemos sobrecarregar outros operadores também. A função especial que precisamos implementar está tabulada abaixo.

Operador Expressão Internamente
Adição p1 + p2 p1.__add__(p2)
Subtração p1 - p2 p1.__sub__(p2)
Multiplicação p1 * p2 p1.__mul__(p2)
Poder p1 ** p2 p1.__pow__(p2)
Divisão p1 / p2 p1.__truediv__(p2)
Divisão de Andar p1 // p2 p1.__floordiv__(p2)
Restante (módulo) p1 % p2 p1.__mod__(p2)
Shift à esquerda bit a bit p1 << p2 p1.__lshift__(p2)
Shift à direita bit a bit p1>> p2 p1.__rshift__(p2)
E bit a bit p1 & p2 p1.__and__(p2)
OR bit a bit p1 | p2 p1.__or__(p2)
XOR bit a bit p1 p2 p1.__xor__(p2)
NÃO bit a bit ~p1 p1.__invert__()

Sobrecarregando operadores de comparação

Python não limita a sobrecarga de operador apenas a operadores aritméticos. Podemos sobrecarregar os operadores de comparação também.

Suponha que queremos implementar o símbolo de menor que <em nossa Pointclasse.

Vamos comparar a magnitude desses pontos da origem e retornar o resultado para este propósito. Ele pode ser implementado da seguinte maneira.

 # 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)

Artigos interessantes...