CodeGym /Cursos /Python SELF PT /Sobrecarga de Operadores

Sobrecarga de Operadores

Python SELF PT
Nível 20 , Lição 0
Disponível

6.1 Métodos Mágicos

A sobrecarga de operadores em Python permite definir ou modificar o comportamento dos operadores internos (por exemplo, +, -, *, /) para as classes do usuário. Isso é feito através de métodos especiais, que também são chamados de métodos mágicos.

Por exemplo, na sua classe você pode sobrecarregar operadores de comparação:

Operador Método sem sublinhado Assinatura do 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)

Suponha que você escreveu sua própria classe e quer que os objetos dessa classe sejam comparados exatamente como você precisa. Você só precisa implementar na sua classe o método «__eq__», e o Python vai chamá-lo toda vez que objetos da sua classe forem comparados no código.

Exemplo:


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)  # Vai imprimir: True
print(v1 == v3)  # Vai imprimir: False

Toda vez que você compara dois dos seus objetos, o Python verifica se eles têm a função «__eq__» implementada. Se sim, ele a chama. Se não, ele vai simplesmente comparar as referências dos objetos.

No exemplo acima, o que está escrito é (apenas adicionando a verificação da presença do método):


# Uso
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2))  # Vai imprimir: True
print(v1.__eq__(v3))  # Vai imprimir: False

6.2 Lista de todos os operadores

No total, existem 6 grupos de operadores disponíveis para sobrecarga.

Operadores aritméticos:

Operador Método sem sublinhado Assinatura do 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 comparação:

Operador Método sem sublinhado Assinatura do 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 sem sublinhado Assinatura do método
& and __and__(self, other)
| or __or__(self, other)
^ xor __xor__(self, other)
~ invert __invert__(self)

Operadores de indexação e fatias:

Operador Método
obj[key] __getitem__(self, key)
obj[key] = value __setitem__(self, key, value)
del obj[key] __delitem__(self, key)

Operadores unários:

Operador Método
- __neg__(self)
+ __pos__(self)
abs() __abs__(self)
~ __invert__(self)

Operadores de atribuição:

Operador Método
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

Talvez seja por isso que o Python é tão lento – cada vez que um operador é executado ele procura uma função equivalente na classe e em todos os seus pais. Mas isso permite escrever o código mais compacto do mundo :)

6.3 Operador de Indexação

O fato de que você pode comparar objetos ou subtrair conjuntos é de certo modo óbvio. E você mesmo vai perceber isso se estiver escrevendo uma classe que pressupõe operações lógicas ou matemáticas sobre ela.

Quero discutir com vocês um exemplo interessante – o operador de indexação. Vamos começar direto com o código de exemplo:


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])  # Vai imprimir: 2
c_list[1] = 10
print(c_list)  # Vai imprimir: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list)  # Vai imprimir: [1, 3, 4, 5]

Aqui vemos um exemplo de três operações:

  • Leitura de dados através do índice
  • Escrita de dados através do índice
  • E até mesmo exclusão de dados através do índice.

E afinal, não é necessário que os dados internos sejam armazenados na forma de uma lista. Ou que o índice tenha que ser um número. Por exemplo, a classe dictionary (dicionário) é exatamente assim que é implementada.

Criando SuperList

Lembra da classe list? Você pode atribuir elementos a ela, mas apenas com aqueles índices que já existem. Vamos fazer nossa própria classe, chamá-la de SuperList, onde podemos acessar os elementos por qualquer índice:

  • Se o índice < 0, vamos inserir o elemento no início
  • Se o índice >= len, vamos adicionar o elemento no final
  • Nos outros casos, simplesmente retornar o elemento

Exemplo:


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]

Então, a sobrecarga de índices é uma ótima possibilidade, e recomendo que use na prática. E por hoje é só.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION