Atualizado: 04/11/2024

Sobrecarga de Operadores - Python

O Python permite definir operadores internos para suas classes, como adição, subtração, entre outros. Para isso, o módulo operator contém uma série de funções:

OperaçãoSintaxeFunção
Adiçãoa + b__add__(a, b)
Uniãoseq1 + seq2__concat__(seq1, seq2)
Verificação de presençaobj in seq__contains__(seq, obj)
Divisão reala / b__truediv__(a, b)
Divisão inteiraa // b__floordiv__(a, b)
Operação bit a bit ANDa & b__and__(a, b)
Operação bit a bit XORa ^ b__xor__(a, b)

Para ver a lista completa de operadores e funções, você pode consultar a documentação oficial.

Para definir um operador específico para uma classe, ela deve implementar a função correspondente. Por exemplo, para definir o operador de adição, implementamos a função __add__() dentro da classe. Veja o exemplo abaixo:

class Counter:
    def __init__(self, value):
        self.value = value

    # redefinindo o operador de adição
    def __add__(self, other):
        return Counter(self.value + other.value)
     
counter1 = Counter(5)
counter2 = Counter(15)
counter3 = counter1 + counter2
print(counter3.value)       # Saída: 20

Neste exemplo, a classe Counter possui o atributo value, representando um número específico. Definimos o operador de adição para o tipo Counter usando a função __add__. Isso permite somar dois objetos Counter, retornando um novo objeto Counter com a soma dos valores dos atributos value dos objetos envolvidos.

Essa implementação não é a única forma de usar o operador de adição. No exemplo anterior, o segundo parâmetro era outro objeto Counter. No entanto, é possível que o segundo parâmetro seja de outro tipo. Por exemplo, caso desejemos somar um objeto Counter a um número:

class Counter:
    def __init__(self, value):
        self.value = value
         
    def __add__(self, other):
        return Counter(self.value + other)
     
counter1 = Counter(5)
counter3 = counter1 + 6
print(counter3.value)       # Saída: 11

Agora, o segundo parâmetro representa um número comum. Ainda assim, a função __add__ retorna um novo objeto Counter com o valor atualizado.

O tipo retornado pelos operadores também não precisa ser estritamente um objeto da classe. Podemos, por exemplo, retornar apenas um número:

class Counter:
    def __init__(self, value):
        self.value = value
         
    def __add__(self, other):
        return self.value + other
     
counter1 = Counter(5)
result = counter1 + 7
print(result)       # Saída: 12

Veracidade de um Objeto

A definição da função __bool__ permite estabelecer a veracidade de um objeto ou convertê-lo implicitamente para True ou False. Veja o exemplo:

class Counter:
    def __init__(self, value):
        self.value = value
    def __bool__(self):
        return self.value > 0
     
def test(counter):
    if counter:
        print("Counter = True")
    else:
        print("Counter = False")
     
counter1 = Counter(3)
test(counter1)              # Saída: Counter = True
 
counter2 = Counter(-3)
test(counter2)              # Saída: Counter = False

Aqui, consideramos que, se value for menor que 1, o objeto Counter será False. Para valores positivos, ele será True. Dessa forma, podemos usar Counter em estruturas condicionais e de repetição, como no exemplo abaixo, onde usamos um objeto Counter como condição em um loop while:

class Counter:
    def __init__(self, value):
        self.value = value
    def __bool__(self):
        return self.value > 0
     
counter1 = Counter(3)
 
while counter1:
    print("Counter1:", counter1.value)
    counter1.value -= 1

Aqui, o loop while será executado enquanto counter1 tiver valor verdadeiro (enquanto value for maior que zero).

Operadores que Retornam Valor Booleano

Algumas operações retornam um valor lógico True ou False, como as operações de comparação:

class Counter:
    def __init__(self, value):
        self.value = value
         
    def __gt__(self, other):
        return self.value > other.value

    def __lt__(self, other):
        return self.value < other.value
     
counter1 = Counter(1)
counter2 = Counter(2)
     
if counter1 > counter2: 
    print("counter1 é maior que counter2")
elif counter1 < counter2:
    print("counter1 é menor que counter2")
else: 
    print("counter1 e counter2 são iguais")

No exemplo acima, o operador > é implementado pela função __gt__() e < pela função __lt__(). Esses operadores permitem comparar o atributo value entre dois objetos Counter.

Operadores de Indexação

Certos operadores permitem acessar um objeto por meio de índice usando colchetes ([]), como em obj[index]. Esses operadores são geralmente usados para coleções, mas podem ser aplicados a qualquer objeto. Veja um exemplo de indexação personalizada para acessar atributos específicos:

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age
         
    def __getitem__(self, prop):
        if prop == "name": return self.__name
        elif prop == "age": return self.__age
        return None
     
tom = Person("Tom", 39)
 
print("Name:", tom["name"])     # Name: Tom
print("Age:", tom["age"])       # Age: 39
print("Id:", tom["id"])         # Id: None

Aqui, a classe Person possui dois atributos privados, __name e __age. A função __getitem__() permite acessar esses atributos com índices personalizados, como "name" ou "age", retornando None se o índice não corresponder a um atributo válido.

Verificação de Existência com o Operador in

O operador in pode verificar a presença de um valor em uma sequência ou coleção:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
         
    def __contains__(self, prop):
        if prop == "name" or prop == "age": return True
        return False
     
tom = Person("Tom", 39)
print("name" in tom)        # True
print("id" in tom)          # False

A função __contains__() implementa o operador in, verificando se a string dada representa um atributo da classe. Nesse caso, "name" in tom retorna True, enquanto "id" in tom retorna False.

Implementação de Operadores em Pares

Alguns operadores de comparação, como == e !=, são convenientes de serem implementados em pares, aproveitando um operador para definir o outro, evitando duplicação de lógica:

class Counter:
    def __init__(self, value):
        self.value = value
     
    def __eq__(self, other): return self.value == other.value
    def __ne__(self, other): return not (self == other)
     
    def __gt__(self, other): return self.value > other.value
    def __le__(self, other): return not (self > other)
     
    def __lt__(self, other): return self.value < other.value
    def __ge__(self, other): return not (self < other)
         
c1 = Counter(1)
c2 = Counter(2)
 
print(c1 == c2)     # False
print(c1 != c2)     # True
print(c1 < c2)      # True
print(c1 >= c2)     # False

Neste exemplo, o operador != inverte o resultado do operador ==, e os operadores >= e <= são definidos como a negação dos operadores < e q, respectivamente. Isso permite uma implementação mais enxuta e evita duplicação de código.

Conclusão

Esses métodos de sobrecarga de operadores no Python permitem definir comportamentos customizados e enriquecem a experiência com objetos de classes personalizadas, tornando-as mais intuitivas para comparação, verificação de existência e acesso direto a propriedades.

Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com