Sobrecarga do operador Python

Resumo : neste tutorial, você aprenderá sobre sobrecarga de operadores Python e como usá-la para fazer seus objetos funcionarem com operadores integrados.

Introdução à sobrecarga do operador Python

Suponha que você tenha uma classe de ponto 2D com atributos de coordenadas x e y :

class Point2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'Linguagem de código:  Python  ( python )

Para adicionar dois objetos Point2D, você pode definir um add()método da seguinte forma:

class Point2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'

    def add(self, point):
        if not isinstance(point, Point2D):
            raise ValueError('The other must be an instance of the Point2D')

        return Point2D(self.x + point.x, self.y + point.y)Linguagem de código:  Python  ( python )

O add()método gera um erro se o ponto não for uma instância da Point2Dclasse. Caso contrário, ele retorna um novo Point2Dobjeto cujas coordenadas xey são as somas xe as ycoordenadas de dois pontos.

O seguinte cria duas instâncias da Point2Dclasse e usa o add()método para adicionar dois pontos:

a = Point2D(10, 20)
b = Point2D(15, 25)
c = a.add(b)

print(c)Linguagem de código:  Python  ( python )

Saída:

(25,45)Linguagem de código:  Python  ( python )

Este código funciona perfeitamente bem. Mas Python tem uma maneira melhor de implementá-lo. Em vez de usar o add()método, você pode usar o operador interno (+) assim:

c = a + bLinguagem de código:  Python  ( python )

Quando você usa o +operador no Point2Dobjeto, Python chamará o método especial __add__()no objeto. As seguintes chamadas são equivalentes:

c = a + b
c = a.__add__(b)Linguagem de código:  Python  ( python )

O __add__()método deve retornar uma nova instância do Point2Dobjeto.

A capacidade de usar o operador integrado ( +) em um tipo personalizado é conhecida como sobrecarga de operador.

A seguir mostra a Point2Dclasse que implementa o __add__()operador especial para dar suporte ao +operador:

class Point2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'

    def __add__(self, point):
        if not isinstance(point, Point2D):
            raise ValueError('The other must be an instance of the Point2D')

        return Point2D(self.x + point.x, self.y + point.y)


if __name__ == '__main__':
    a = Point2D(10, 20)
    b = Point2D(15, 25)
    c = a + b
    print(c)Linguagem de código:  Python  ( python )

Saída:

(25,45)

Métodos especiais para sobrecarga do operador

A seguir mostramos os operadores com seus métodos especiais correspondentes:

Operador Métodos Especiais
+ __add__(próprio, outro)
__sub__(próprio, outro)
* __mul__(próprio, outro)
/ __truediv__(próprio, outro)
// __floordiv__(próprio, outro)
% __mod__(próprio, outro)
** __pow__(próprio, outro)
>> __rshift__(próprio, outro)
<< __lshift__(próprio, outro)
& __e__(próprio, outro)
| __ou__(próprio, outro)
^ __xor__(próprio, outro)

Por exemplo, você pode implementar o __sub__()método no Point2D para suportar a subtração ( -) de dois pontos:

class Point2D:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f'({self.x},{self.y})'

    def __add__(self, point):
        if not isinstance(point, Point2D):
            raise ValueError('The other must be an instance of the Point2D')

        return Point2D(self.x + point.x, self.y + point.y)

    def __sub__(self, other):
        if not isinstance(other, Point2D):
            raise ValueError('The other must be an instance of the Point2D')

        return Point2D(self.x - other.x, self.y - other.y)


if __name__ == '__main__':
    a = Point2D(10, 20)
    b = Point2D(15, 25)
    c = b - a
    print(c)Linguagem de código:  Python  ( python )

Sobrecarregando operadores locais

Algumas operadoras possuem a versão local. Por exemplo, a versão local de + é +=.

Para o tipo imutável como tuple , uma string, um número, os operadores inplace realizam cálculos e não atribuem o resultado de volta ao objeto de entrada.

Para o tipo mutável, o operador inplace executa as atualizações diretamente nos objetos originais. A atribuição não é necessária.

Python também fornece uma lista de métodos especiais que permitem sobrecarregar o operador inplace:

Operador Método Especial
+= __iadd__(próprio, outro)
-= __isub__(próprio, outro)
*= __imul__(próprio, outro)
/= __itruediv__(próprio, outro)
//= __ifloordiv__(próprio, outro)
%= __imod__(próprio, outro)
**= __ipow__(próprio, outro)
>>= __irshift__(próprio, outro)
<<= __ilshift__(próprio, outro)
&= __iand__(próprio, outro)
|= __ior__(próprio, outro)
^= __ixor__(próprio, outro)

Vejamos um exemplo de sobrecarga do +=operador.

Suponha que você tenha um objeto carrinho e queira adicionar um item ao carrinho. Para fazer isso, você pode definir um add()método para a Cartclasse e usá-lo assim:

cart.add(item)Linguagem de código:  Python  ( python )

Alternativamente, você pode implementar o +=operador na Cartclasse. Ele permite que você adicione um item ao carrinho da seguinte forma:

cart += itemLinguagem de código:  Python  ( python )

Para suportar o operador +=, você precisa implementar o __iadd__método especial na Cartclasse.

Primeiro, defina a Itemclasse que possui três atributos nome, quantidade e preço. Além disso, possui uma propriedade amount que retorna o subtotal do item:

class Item:
    def __init__(self, name, qty, price):
        self.name = name
        self.qty = qty
        self.price = price

    @property
    def amount(self):
        return self.qty * self.price

    def __str__(self):
        return f'{self.name} {self.qty} ${self.price} ${self.amount}'Linguagem de código:  Python  ( python )

Segundo, defina a Cartclasse que implementa o __iadd__método:

class Cart:
    def __init__(self):
        self.items = []

    def __iadd__(self, item):
        if not isinstance(item, Item):
            raise ValueError('The item must be an instance of Item')

        self.items.append(item)
        return self

    @property
    def total(self):
        return sum([item.amount for item in self.items])

    def __str__(self):
        if not self.items:
            return 'The cart is empty'

        return '\n'.join([str(item) for item in self.items])Linguagem de código:  Python  ( python )

No __iadd__método, levantamos a ValueErrorse o item não for uma instância da Itemclasse. Caso contrário, adicionamos o item ao atributo da lista de itens.

A propriedade total retorna a soma de todos os itens.

O __str__método retorna a string 'The cart is empty'se o carrinho não tiver nenhum item. Caso contrário, ele retorna uma string que contém todos os itens separados por uma nova linha.

Terceiro, use o +=operador para adicionar um item ao carrinho:

if __name__ == '__main__':
    cart = Cart()

    cart += Item('Apple', 5, 2)
    cart += Item('Banana', 20, 1)
    cart += Item('Orange', 10, 1.5)

    print(cart)
    # print the total line
    print('-' * 30)
    print('Total: $', cart.total)Linguagem de código:  Python  ( python )

Saída:

Apple   5       $2      $10
Banana  20      $1      $20
Orange  10      $1.5    $15.0
------------------------------
Total: $ 45.0Linguagem de código:  Python  ( python )

Resumo

  • A sobrecarga do Opeartor permite que uma classe use operadores integrados.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *