Herança & MRO
Python suporta herança múltipla e resolve métodos com a Ordem de Resolução de Métodos (MRO). super() percorre essa ordem - essencial para cadeias cooperativas de __init__ em mixins.
Receita
class LogMixin:
def log(self, msg: str) -> None:
print(f"[{self.__class__.__name__}] {msg}")
class Service(LogMixin):
def run(self) -> None:
self.log("starting")Quando usar isso:
- Compartilhar comportamento transversal via mixins (logging, serialização)
- Estender classes base de frameworks (modelos Django, ABCs)
- Depurar sobrescritas de métodos inesperadas em hierarquias
- Projetar APIs de plugins com o padrão template method
Exemplo de Trabalho
class Base:
def __init__(self) -> None:
self.base_init = True
class TrackingMixin:
def __init__(self, *args, **kwargs) -> None:
self.tracked = True
super().__init__(*args, **kwargs)
class TimestampMixin:
def __init__(self, *args, **kwargs) -> None:
self.timestamped = True
super().__init__(*args, **kwargs)
class Event(TrackingMixin, TimestampMixin, Base):
pass
if __name__ == "__main__":
e = Event()
print(e.tracked, e.timestamped, e.base_init)
print(Event.mro())O que isso demonstra:
- Chamadas cooperativas de
super().__init__para cada classe no MRO uma vez - Mixins adicionam comportamento na frente sem árvores profundas
Event.mro()mostra a ordem de resolução para depuração- Todos os
__init__dos mixins rodam antes que a cadeiaBaseseja completada
Mergulho Profundo
Como Funciona
- Linearização C3 - MRO respeita precedência local e monotonicidade.
- Proxy
super()- Pula para a próxima classe no MRO, não necessariamente o pai direto. - Sobrescrita de método - Método da subclasse sombreia a base;
super()chama a próxima implementação. - Problema do diamante - C3 garante que cada classe apareça uma vez em uma ordem sensata.
- Cadeia de
__init__- Toda classe no padrão cooperativo deve chamarsuper().__init__.
Inspecionar MRO
HelpfulClass.mro() # lista de classes na ordem de busca
HelpfulClass.__mro__ # forma de tuplaNotas Python
# chamada explícita de sobrescrita
class Child(Parent):
def save(self) -> None:
super().save()
self.post_save_hook()Armadilhas
super()faltando no mixin - Quebra a cadeia - algumas bases nunca inicializam. Correção: Sempre usesuper().__init__(*args, **kwargs)em mixins.- Torres de herança profundas - Sobrescritas frágeis. Correção: Composição ou design baseado em protocolo.
- Atributos de classe mutáveis herdados - Lista compartilhada na subclasse modifica a visão da classe pai. Correção: Defina por instância em
__init__. - Mistura de bases não relacionadas - MRO e superfície de API confusas. Correção: Mixins pequenos com uma responsabilidade.
super()sem bases cooperativas - Classes legadas que não chamamsuperquebram o padrão. Correção: Adapte ou evite herança múltipla.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Composição | Relacionamentos "tem-um" | Polimorfismo "é-um" verdadeiro |
| Tipagem de protocolo | Interfaces estruturais | Necessidade de implementação compartilhada |
| Funções + dispatch | Reutilização de comportamento simples | O padrão template method se encaixa |
| Herança única | Hierarquia clara | Apenas uma camada de mixin necessária |
FAQs
O que é MRO?
Ordem em que Python busca atributos/métodos nas bases. Imprima com Class.mro().
Por que `super()` e não `Parent.method()`?
super() respeita o MRO para herança múltipla - um pai codificado explicitamente ignora mixins cooperativos.
Quantos mixins?
Poucos e pequenos são aceitáveis. Muitos mixins sinalizam um "cheiro" de design - considere composição.
Posso herdar de duas classes não relacionadas?
Tecnicamente sim - observe a clareza da API e as surpresas do MRO. Frequentemente, a composição é mais clara.
Classe base abstrata na hierarquia?
Uma ABC pode ficar no MRO, exigindo métodos antes das classes concretas.
Regras para sobrescrever `__init__`?
Chame super().__init__ a menos que esteja substituindo deliberadamente toda a cadeia - documente o motivo.
Atributo de resolução de métodos?
Atributos de instância sombreiam métodos de classe - descritores e descritores de dados adicionam nuances.
Herança de `__slots__`?
Os slots da classe filha devem incluir uma declaração vazia dos slots da classe pai - complexo; leia a documentação antes de combinar.
Testando MRO?
Afirme Class.mro()[1] == ExpectedParent quando a ordem do mixin for crítica.
Herança de framework?
Padrões como Django/FastAPI frequentemente herdam de classes de framework - siga a documentação do framework para chamadas super.
Relacionados
- Classes Base Abstratas - ABCs em hierarquias
- Protocolos e Tipagem Estrutural - alternativa à herança
- Métodos de Classe vs. Instância vs. Estáticos -
supercom classmethods - Boas Práticas de Python Orientado a Objetos - orientação sobre composição
Versões do Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.