Polimorfismo

polimorfismo é um dos pilares da Programação Orientada a Objetos (POO) que permite que métodos com o mesmo nome se comportem de maneira diferente em classes distintas. Em Python, ele é implementado principalmente por meio de:

  1. Sobrescrita de métodos (herança)
  2. Duck Typing (tipagem dinâmica)
  3. Sobrecarga de operadores

Polimorfismo por sobrescrita de métodos

Quando uma subclasse redefine um método da superclasse, adaptando-o ao seu contexto.

class Animal:
    def emitir_som(self):
        return "Som genérico"

class Cao(Animal):
    def emitir_som(self):  # Sobrescreve o método da superclasse
        return "Au au!"

class Gato(Animal):
    def emitir_som(self):  # Sobrescreve o método da superclasse
        return "Miau!"

# Uso
gato = Gato()
gato.emitir_som()
cao = Cao()
cao.emitir_som()

Output:

Au au!

Miau!

Tanto Cao quanto Gato herdam emitir_som() de Animal, mas cada um implementa seu próprio comportamento.

Polimorfismo por tipagem dinâmica

O Python não verifica tipos rigidamente. Se um objeto tem o método necessário, ele pode ser usado, mesmo sem herança.

class Circulo:
    def area(self, raio):
        return 3.14 * raio ** 2

class Quadrado:
    def area(self, lado):
        return lado ** 2

def calcular_area(forma, medida):
    return forma.area(medida)

# Uso
print(calcular_area(Circulo(), 5))  # Saída: 78.5
print(calcular_area(Quadrado(), 4)) # Saída: 16

A função calcular_area() aceita qualquer objeto com o método area(), independentemente da classe.

Polimorfismo por sobrecarga de operadores

O polimorfismo em Python por sobrecarga de operadores permite que operadores padrão, como +, -, *, etc., tenham comportamentos personalizados quando aplicados a objetos de classes definidas pelo usuário. Isso é feito implementando métodos especiais conhecidos como “métodos mágicos” ou “dunder methods” (como __add__, __eq__, etc.) nas suas classes.

Como funciona a sobrecarga de operadores em Python:

  • Você define métodos especiais dentro da sua classe para “ensinar” o Python como deve se comportar ao usar um operador com objetos dessa classe.
  • Por exemplo, ao implementar o método __add__, permite que o operador + funcione entre dois objetos da sua classe. O mesmo vale para outros operadores (__sub__ para -, __mul__ para *, etc.).
  • Exemplo:
class Fracao:
def __init__(self, numerador, denominador):
self.numerador = numerador
self.denominador = denominador

def __add__(self, outro):
novo_num = self.numerador * outro.denominador + outro.numerador * self.denominador
novo_den = self.denominador * outro.denominador
return Fracao(novo_num, novo_den)

Neste exemplo, pode somar objetos Fracao usando o operador +, e o método __add__ será chamado para realizar a lógica específica que você definiu.

Polimorfismo por sobrecarga de operadores:

  • O mesmo operador (+) pode assumir comportamentos distintos, dependendo do tipo dos objetos envolvidos: pode somar inteiros, concatenar strings ou, se você sobrecarregar, realizar operações específicas em objetos de sua classe.
  • Esse é um exemplo prático de polimorfismo, pois o operador tem múltiplas “formas” (comportamentos), dependendo do contexto.

Caveat especial em Python:

  • Diferente de outras linguagens, Python não suporta sobrecarga de métodos pelo número ou tipo de argumentos (assinatura), mas permite a sobrecarga de operadores via métodos especiais.
  • A verificação de tipo é flexível: Python espera que o método esteja disponível no objeto (“duck typing”), não é necessário herdar de uma classe específica.

Exemplo rápido de uso:

na = Fracao(1, 2)
b = Fracao(1, 3)
c = a + b # Usa Fracao.__add__

Neste caso, a + b funciona porque Fracao define __add__.

Resumo dos métodos especiais (mais comuns de operadores):

  • __add__(self, other) → +
  • __sub__(self, other) → –
  • __mul__(self, other) → *
  • __eq__(self, other) → ==
  • __lt__(self, other) → <
  • …e muitos outros.