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 índiceEscrita de dados através do índiceE 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ícioSe o índice >= len, vamos adicionar o elemento no finalNos 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ó.
GO TO FULL VERSION