Principais Pontos
- A função `super()` em Python possibilita a invocação de métodos de classes superiores a partir de subclasses, simplificando a implementação de herança e a substituição de métodos.
- O funcionamento da função `super()` está intrinsecamente ligado à Ordem de Resolução de Método (MRO) em Python, que estabelece a sequência na qual as classes ancestrais são consultadas na busca por métodos ou atributos.
- A utilização de `super()` em construtores de classes é uma prática comum para inicializar atributos gerais na classe pai e atributos mais específicos na classe filha. A omissão do uso de `super()` pode ocasionar resultados inesperados, como a ausência de inicialização de atributos.
Um dos pilares do Python é seu paradigma de Programação Orientada a Objetos (POO), que possibilita a modelagem de entidades do mundo real e suas relações.
Ao lidar com classes em Python, é comum empregar a herança e sobrescrever atributos ou métodos de uma superclasse. O Python disponibiliza a função `super()` que permite acionar os métodos da superclasse a partir da subclasse.
O que é `super()` e por que ela é necessária?
Através da herança, é possível criar novas classes em Python que herdam características de classes já existentes. Também é viável substituir métodos da superclasse na subclasse, oferecendo implementações alternativas. No entanto, em vez de simplesmente substituir, pode-se desejar adicionar novas funcionalidades às já existentes. É nesse contexto que `super()` se mostra útil.
A função `super()` pode ser usada para acessar atributos da superclasse e invocar seus métodos. `Super()` é essencial na programação orientada a objetos, pois facilita a implementação de herança e a substituição de métodos.
Como a função `super()` opera?
Internamente, o funcionamento de `super()` está intimamente atrelado à Ordem de Resolução de Método (MRO) em Python, que é determinada pelo algoritmo de Linearização C3.
Veja como `super()` funciona:
Utilizando `super()` em um construtor de classe
O uso de `super()` em um construtor de classe é uma prática comum, já que frequentemente se deseja inicializar atributos comuns na classe pai e atributos mais específicos na classe filha.
Para ilustrar, considere a definição de uma classe Python, `Pai`, da qual uma classe `Filho` herda:
class Pai: def __init__(self, primeiro_nome, sobrenome): self.primeiro_nome = primeiro_nome self.sobrenome = sobrenome class Filho(Pai): def __init__(self, primeiro_nome, sobrenome, idade, hobbie): super().__init__(primeiro_nome, sobrenome) self.idade = idade self.hobbie = hobbie def get_info(self): return f"Nome do Filho: {self.primeiro_nome} {self.sobrenome}, \ Idade do Filho: {self.idade}, Hobbie do Filho: {self.hobbie}" filho = Filho("Pius", "Effiong", 25, "Tocar Guitarra") print(filho.get_info())
Dentro do construtor de `Filho`, a chamada para `super().__init__()` invoca o construtor da classe `Pai`, passando `primeiro_nome` e `sobrenome` como parâmetros. Isso garante que a classe `Pai` possa definir os atributos de nome corretamente, mesmo em um objeto `Filho`.
Se a função `super()` não for chamada em um construtor de classe, o construtor da classe pai não será executado. Isso pode levar a resultados indesejados, como a ausência de inicializações de atributos ou a configuração incompleta do estado da classe pai:
... class Filho(Pai): def __init__(self, primeiro_nome, sobrenome, idade, hobbie): self.idade = idade self.hobbie = hobbie ...
Caso se tente acionar o método `get_info` neste cenário, um `AttributeError` será gerado, pois os atributos `self.primeiro_nome` e `self.sobrenome` não foram inicializados.
Utilizando `super()` em métodos de classe
A função `super()` pode ser empregada em outros métodos, além dos construtores, da mesma maneira. Isso viabiliza a extensão ou a substituição do comportamento do método da superclasse.
class Pai: def falar(self): return "Olá do Pai" class Filho(Pai): def falar(self): saudacao_pai = super().falar() return f"Olá do Filho\n{saudacao_pai}" filho = Filho() saudacao_filho = filho.falar() print(saudacao_filho)
A classe `Filho` herda de `Pai` e possui seu próprio método `falar`. O método `falar` da classe `Filho` utiliza `super().falar()` para acionar o método `falar` da classe `Pai`. Isso possibilita a inclusão da mensagem da classe pai, enquanto a estende com uma mensagem específica para a classe filha.
A omissão da função `super()` em um método que substitui outro implica que a funcionalidade presente no método da classe pai não terá efeito. Isso resulta em uma substituição total do comportamento do método, o que pode levar a um comportamento indesejado.
Compreendendo a Ordem de Resolução do Método
A Ordem de Resolução de Método (MRO) é a sequência na qual Python busca classes ancestrais quando um método ou atributo é acessado. O MRO auxilia Python a determinar qual método acionar quando existem múltiplas hierarquias de herança.
class Nigeria(): def cultura(self): print("Cultura da Nigéria") class Africa(): def cultura(self): print("Cultura da África")
Veja o que acontece quando uma instância da classe `Lagos` é criada e o método `cultura` é chamado:
A saída apresenta a Ordem de Resolução de Método de `Lagos`, da esquerda para a direita.
Armadilhas comuns e práticas recomendadas
Ao trabalhar com `super()`, é importante estar ciente de algumas armadilhas comuns para evitar.
Utilize `super()` da maneira correta
A função `super()` do Python é um recurso poderoso quando se trabalha com herança e substituição de métodos. A compreensão do funcionamento de `super()` e a observância das práticas recomendadas permitirão a criação de códigos mais sustentáveis e eficientes em seus projetos Python.