Utilizar a função super() em classes Python
Key Takeaways
A utilização da função super()
em Python facilita a invocação de métodos numa subclasse acedendo à sua superclasse, melhorando assim o processo de implementação da herança e das substituições de métodos de uma forma elegante.
A função super()
tem uma ligação significativa com a Ordem de Resolução de Métodos (MRO) em Python, que governa a sequência em que as classes ancestrais são escrutinadas quanto a métodos e propriedades durante a resolução de métodos.
A utilização de super()
no construtor de uma classe é uma abordagem habitual para estabelecer características partilhadas na classe-mãe e definir traços mais particulares na classe subordinada. A não implementação de super()
pode resultar em resultados indesejados, incluindo a omissão da inicialização de atributos.
Um dos aspectos fundamentais da linguagem de programação Python é o seu paradigma de Programação Orientada para Objectos (POO), que permite a criação de modelos que representam objectos da vida real e as suas interligações de forma estruturada.
No contexto da programação com Python, é comum utilizar a herança para modificar ou substituir características ou funções da entidade-mãe de uma classe. A linguagem oferece um mecanismo conveniente conhecido como a função “super()”, que permite efetuar chamadas aos métodos da classe superior a partir da classe subordinada.
O que é super() e porque é que precisa dela?
A herança de uma classe existente permite a criação de uma nova classe com atributos e comportamentos semelhantes através do processo de herança. Além disso, pode-se optar por substituir métodos específicos dentro da subclasse para fornecer sua própria implementação exclusiva. Embora esta nova funcionalidade possa ser desejável, há casos em que é preferível utilizar simultaneamente as funcionalidades originais e as recém-implementadas. Nesses casos, a utilização da função super()
permite a integração de ambos os conjuntos de capacidades na subclasse.
Para utilizar os atributos e métodos de uma superclasse na programação orientada para objectos, pode utilizar-se a função super()
. Esta função desempenha um papel crucial, pois facilita a implementação da herança e da substituição de métodos, que são conceitos fundamentais na programação orientada para objectos.
Como é que super() funciona?
Internamente, o comportamento da função super()
está interligado com o conceito de Ordem de Resolução de Métodos (MRO), um mecanismo que é determinado pelo algoritmo de linearização C3 em Python.
Eis como funciona a função super():
Ao chamar super()
dentro de um método de uma subclasse em Python, a linguagem identifica automaticamente tanto a classe atual, que contém o método invocado, como a instância dessa classe representada por self
.
⭐ Determinar a superclasse : super() recebe dois argumentos - a classe atual e a instância - que não é necessário passar explicitamente. Ele usa essas informações para determinar a superclasse para delegar a chamada do método. Ele faz isso examinando a hierarquia de classes e o MRO.
Uma vez identificada uma superclasse, a função super()
permite a invocação dos seus métodos como se estivessem a ser chamados diretamente da subclasse. Esta capacidade facilita tanto a extensão como a substituição de métodos da superclasse, utilizando sempre a implementação original fornecida pela superclasse.
Usando super() em um construtor de classe
Incorporar o uso do método super() nos construtores de classes é uma abordagem predominante, pois permite a inicialização de propriedades compartilhadas entre classes irmãs, ao mesmo tempo em que permite características únicas em cada descendência individual.
Para ilustrar o conceito de herança na programação orientada a objectos utilizando Python, podemos criar uma classe “Pai” que serve de classe base para outra classe chamada “Filho”. A classe “Filho” herdará propriedades e métodos da sua classe-mãe, a classe “Pai”, demonstrando assim como a herança permite a reutilização e a modularidade do código.
class Father:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
class Son(Father):
def __init__(self, first_name, last_name, age, hobby):
# Call the parent class constructor (Father)
super().__init__(first_name, last_name)
self.age = age
self.hobby = hobby
def get_info(self):
return f"Son's Name: {self.first_name} {self.last_name}, \
Son's Age: {self.age}, Son's Hobby: {self.hobby}"
# Create an instance of the Son class
son = Son("Pius", "Effiong", 25, "Playing Guitar")
# Access attributes
print(son.get_info())
Dentro dos limites do construtor da classe Filho
, o imperativo de invocar os auspícios da sua classe-mãe é executado através do ato prodigioso de invocar a função super()
. Esta ação fundamental desencadeia a iniciação do construtor da classe paterna Pai
, oferecendo dois estimados qualificadores primordiais sob a forma das variáveis nome_primeiro
e nome_último
. Desta forma, a classe Pai
mantém a capacidade de obter e atribuir com exatidão estas designações nominais, não obstante a instanciação de um Filho
.
Nos casos em que o método super()
não é invocado dentro da construção
...
class Son(Father):
def __init__(self, first_name, last_name, age, hobby):
self.age = age
self.hobby = hobby
...
Caso tente invocar o método get_info
neste momento, isso resultará na geração de um AttributeError
, uma vez que o self. first_name
e self.last_name
ainda não foram inicializados.
Usando super() em métodos de classe
Pode-se empregar a utilização da função super() não apenas dentro dos limites dos procedimentos do construtor, mas também em uma série diversificada de métodos para aumentar ou substituir a funcionalidade da abordagem metodológica da classe pai.
class Father:
def speak(self):
return "Hello from Father"
class Son(Father):
def speak(self):
# Call the parent class's speak method using super()
parent_greeting = super().speak()
return f"Hello from Son\n{parent_greeting}"
# Create an instance of the Son class
son = Son()
# Call the speak method of the Son class
son_greeting = son.speak()
print(son_greeting)
A classe Son
em Python foi concebida para herdar propriedades e métodos da sua classe-mãe ou Father
, incluindo o método speak()
. Ao utilizar a função super().speak()
dentro do método speak()
da classe Son
, pode efetivamente invocar o método original speak()
da classe Father
, ao mesmo tempo que incorpora quaisquer informações ou mensagens adicionais exclusivas da classe Son
.
Nos casos em que um método substitui outro sem utilizar a função super()
fornecida, a funcionalidade pretendida da classe-mãe não será executada. Consequentemente, isto pode resultar num comportamento não intencional devido a uma metodologia totalmente nova e distinta que substitui a funcionalidade original.
Compreender a Ordem de Resolução de Métodos
A Ordem de Resolução de Métodos (MRO) refere-se à hierarquia de precedência que determina a ordem pela qual Python irá procurar métodos e atributos ao lidar com estruturas de classes complexas que envolvem herança múltipla. Este mecanismo assegura que o método apropriado é chamado com base nas opções disponíveis nas respectivas classes-mãe, resolvendo assim quaisquer potenciais ambiguidades resultantes de definições sobrepostas.
class Nigeria():
def culture(self):
print("Nigeria's culture")
class Africa():
def culture(self):
print("Africa's culture")
Ao instanciar a classe Lagos e invocar o seu método de cultura, ocorrem vários eventos que contribuem para a funcionalidade geral do objeto. A execução do código passa por várias fases que envolvem a manipulação de dados, a obtenção de informações de fontes externas e a aplicação de vários algoritmos para analisar aspectos culturais com base em parâmetros de entrada fornecidos pelo utilizador ou em valores predefinidos definidos no construtor. O resultado final é uma avaliação exaustiva dos atributos culturais da cidade especificada, representada pela classe Lagos.
Python procura primeiro o método culture
dentro da própria classe Lagos
. Se este método for descoberto e estiver disponível, o algoritmo invoca-o. No entanto, se esse método não existir ou não puder ser acedido, o processo avança para a fase seguinte.
Se a classe Lagos
não tiver um método culture()
, Python irá procurar o método nas classes base da hierarquia de classes, começando pelas classes listadas depois dos dois pontos ( :
), que são herdadas pela classe Lagos
. Neste exemplo, a classe Lagos
é definida para herdar primeiro da classe África
e, em segundo lugar, da classe Nigéria
. Por conseguinte, se a classe Lagos
não contiver a sua própria implementação do método culture()
, Python tentará localizar o método na classe África
antes de procurar na classe Nigéria
.
A procura de um método específico de uma cultura numa determinada hierarquia de classes prossegue através de uma série de classes aninhadas, com cada classe subsequente a ser examinada no caso de o método desejado ser aí encontrado. No caso de o método não ser descoberto no nível inicial de investigação, nomeadamente a classe africana, Python muda o seu foco para a classe mais alta seguinte na estrutura hierárquica, que neste caso corresponde à classe nigeriana. Este processo repete-se à medida que se desce na árvore de classes, estendendo-se da mais geral para a menos específica, até ao momento em que o método procurado não pode ser localizado em nenhuma das superclasses encontradas. Nesse momento, é levantada uma exceção para indicar o resultado infrutífero da pesquisa.
A ordem de resolução de métodos (MRO) para Lagos é apresentada de forma linear, começando da esquerda e progredindo para a direita.
Armadilhas comuns e boas práticas
Ao utilizar a função super()
, é importante estar ciente de alguns potenciais erros para garantir uma experiência suave e eficaz.
⭐ Tenha em atenção a ordem de resolução do método, especialmente em cenários de herança múltipla. Se precisar de usar herança múltipla complexa, deve estar familiarizado com o algoritmo de Linearização C3 que o Python usa para determinar a MRO.
As dependências circulares dentro de uma hierarquia de classes devem ser evitadas, uma vez que podem resultar num comportamento errático e difícil de antecipar.
Ao trabalhar com hierarquias de classes complexas que envolvem o uso da função super()
, é crucial manter uma base de código clara e bem documentada. Isso não apenas garante a funcionalidade adequada, mas também promove a compreensão entre colegas desenvolvedores que podem precisar trabalhar ou modificar o código no futuro. Ao fornecer comentários concisos e informativos, pode melhorar a legibilidade e a manutenção do seu projeto, facilitando a colaboração e reduzindo potenciais erros ou confusões.
Utilizar super() da forma correcta
A utilização da função super() em Python representa um aspeto indispensável do seu paradigma de programação orientado para objectos, particularmente em relação à facilitação de heranças e substituições de métodos. A compreensão dos meandros associados a esta entidade funcional e a adesão às melhores práticas estabelecidas permite o desenvolvimento de aplicações de software mais duradouras e com mais recursos dentro do ecossistema Python.