Da trilha de Python Este conceito ainda não saiu como card do dia. ir para o card de hoje

Python POO Intermediário

Herança e super

Em Python, herança permite que uma classe (subclasse) reutilize e especialize o comportamento de outra (superclasse). A subclasse herda atributos e métodos, podendo sobrescrevê-los. A função super() dá acesso à implementação da superclasse, evitando duplicação de código e permitindo encadear comportamentos.

Quando uma classe herda de várias, Python usa a MRO (Method Resolution Order) para decidir qual método chamar. A MRO é uma ordem linear calculada pelo algoritmo C3, acessível via Classe.__mro__ ou Classe.mro(). super() segue essa ordem, não apenas a superclasse direta.

Além da herança, composição é uma alternativa poderosa: em vez de herdar, a classe contém instâncias de outras classes e delega responsabilidades. Herança é indicada para relações "é um", enquanto composição para "tem um".

Neste card, veremos como usar super() corretamente, entender a MRO e quando preferir composição à herança.

Pontos-chave

  • Herança cria uma relação "é um" e permite reutilizar código da superclasse.
  • super() chama o próximo método na MRO, não necessariamente a superclasse direta.
  • A MRO define a ordem de busca de métodos em herança múltipla; use Classe.mro() para inspecionar.
  • Composição ("tem um") é preferível quando a relação não é de especialização.
  • Sempre chame super().__init__() para inicializar a superclasse corretamente.
heranca_super.py
class Animal:
    def __init__(self, nome):
        self.nome = nome

    def falar(self):
        return "..."

    def apresentar(self):
        return f"Eu sou {self.nome} e faço {self.falar()}"


class Cachorro(Animal):
    def __init__(self, nome, raca):
        super().__init__(nome)  # inicializa Animal
        self.raca = raca

    def falar(self):
        return "Au au!"


class Gato(Animal):
    def __init__(self, nome):
        super().__init__(nome)

    def falar(self):
        return "Miau!"


# Composição: um PetShop tem animais
class PetShop:
    def __init__(self):
        self.animais = []

    def adicionar(self, animal):
        self.animais.append(animal)

    def listar(self):
        for a in self.animais:
            print(a.apresentar())


if __name__ == "__main__":
    rex = Cachorro("Rex", "Labrador")
    mimi = Gato("Mimi")
    print(rex.apresentar())
    print(mimi.apresentar())

    shop = PetShop()
    shop.adicionar(rex)
    shop.adicionar(mimi)
    shop.listar()

    # MRO
    print(Cachorro.mro())

Exercícios

  1. 1
    Fácil

    Herança simples com super()

    Crie uma classe Veiculo com atributo marca e método descricao() que retorna "Veículo da marca X". Depois, crie Carro que herda de Veiculo, adiciona modelo e sobrescreve descricao() chamando super().descricao() e acrescentando " modelo Y".

    Resolver
  2. 2
    Médio

    Herança múltipla e MRO

    Crie duas classes A e B, ambas com método quem_sou(). A retorna "A", B retorna "B". Depois crie C(A, B) que sobrescreve quem_sou() chamando super().quem_sou() e adicionando "C". Imprima o resultado de C().quem_sou() e a MRO de C.

    Resolver
  3. 3
    Desafio

    Composição vs herança

    Implemente um sistema de log que pode ser usado por uma classe Servico. Em vez de herdar de Logger, Servico deve compor com um logger injetado. Crie Logger (com log(msg)) e Servico que recebe um logger no construtor e usa self.logger.log() em um método executar(). Mostre que é possível trocar o logger sem alterar Servico.

    Resolver

Continue estudando