Usando a função super() em classes Python

Principais conclusões

  • A função super() do Python permite chamar métodos de superclasse de uma subclasse, facilitando a implementação de herança e substituição de método.
  • A função super() está intimamente relacionada à Ordem de Resolução de Método (MRO) em Python, que determina a ordem em que as classes ancestrais são pesquisadas em busca de métodos ou atributos.
  • Usar super() em construtores de classe é uma prática comum para inicializar atributos comuns na classe pai e outros mais específicos na classe filha. Deixar de usar super() pode levar a consequências indesejadas, como falta de inicializações de atributos.

Um dos principais recursos do Python é seu paradigma OOP, que você pode usar para modelar entidades do mundo real e seus relacionamentos.

Ao trabalhar com classes Python, você frequentemente usará herança e substituirá atributos ou métodos de uma superclasse. Python fornece uma função super() que permite chamar os métodos da superclasse a partir da subclasse.

O que é super() e por que você precisa dele?

Usando herança, você pode criar uma nova classe Python que herda os recursos de uma classe existente. Você também pode substituir métodos da superclasse na subclasse, fornecendo implementações alternativas. No entanto, você pode querer usar a nova funcionalidade além da antiga, em vez de substituí-la. Neste caso, super() é útil.

Você pode usar a função super() para acessar atributos da superclasse e invocar métodos da superclasse. Super é essencial para programação orientada a objetos porque facilita a implementação de herança e substituição de métodos.

  Guia Rysnc e 11 exemplos para usá-lo de forma eficaz

Como funciona super()?

Internamente, super() está intimamente relacionado à Ordem de Resolução de Método (MRO) em Python, que o algoritmo de Linearização C3 determina.

Veja como super() funciona:

  • Determine a classe e a instância atuais: quando você chama super() dentro de um método de uma subclasse, o Python descobre automaticamente a classe atual (a classe que contém o método que chamou super()) e a instância dessa classe (ou seja, self) .
  • Determine a superclasse: super() recebe dois argumentos – a classe atual e a instância – que você não precisa passar explicitamente. Ele usa essas informações para determinar a superclasse à qual delegar a chamada do método. Isso é feito examinando a hierarquia de classes e o MRO.
  • Invocar o método na Superclasse: Uma vez determinada a superclasse, super() permite que você chame seus métodos como se os estivesse chamando diretamente da subclasse. Isso permite estender ou substituir métodos enquanto ainda usa a implementação original da superclasse.
  • Usando super() em um construtor de classe

    Usar super() em um construtor de classe é uma prática comum, pois muitas vezes você desejará inicializar atributos comuns na classe pai e atributos mais específicos na classe filha.

    Para demonstrar isso, defina uma classe Python, Pai, da qual uma classe Filho herda:

     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):
            
            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}"


    son = Son("Pius", "Effiong", 25, "Playing Guitar")


    print(son.get_info())

    Dentro do construtor Son, a chamada para super().init() invoca o construtor da classe Father, passando-o first_name e last_name como parâmetros. Isso garante que a classe Pai ainda possa definir os atributos de nome corretamente, mesmo em um objeto Filho.

      5 ferramentas para verificar a infraestrutura como código para vulnerabilidades

    Se você não chamar super() em um construtor de classe, o construtor de sua classe pai não será executado. Isso pode levar a consequências não intencionais, como falta de inicializações de atributos ou configuração incompleta do estado da classe pai:

     ...
    class Son(Father):
        def __init__(self, first_name, last_name, age, hobby):
            self.age = age
            self.hobby = hobby
    ...

    Se você tentar chamar o método get_info agora, ele gerará um AttributeError porque os atributos self.first_name e self.last_name não foram inicializados.

    Usando super() em métodos de classe

    Você pode usar super() em outros métodos, além dos construtores, da mesma maneira. Isso permite estender ou substituir o comportamento do método da superclasse.

     class Father:
        def speak(self):
            return "Hello from Father"

    class Son(Father):
        def speak(self):
            
            parent_greeting = super().speak()
            return f"Hello from Son\n{parent_greeting}"


    son = Son()


    son_greeting = son.speak()

    print(son_greeting)

    A classe Son herda do Pai e tem seu método speak. O método speak da classe Son usa super().speak() para chamar o método speak da classe Father. Isso permite incluir a mensagem da classe pai enquanto a estende com uma mensagem específica para a classe filha.

    Deixar de usar super() em um método que substitui outro significa que a funcionalidade presente no método da classe pai não terá efeito. Isso resulta em uma substituição completa do comportamento do método, o que pode levar a um comportamento indesejado.

    Compreendendo a ordem de resolução do método

    Ordem de resolução de método (MRO) é a ordem em que Python pesquisa classes ancestrais quando você acessa um método ou atributo. O MRO ajuda o Python a determinar qual método chamar quando existem múltiplas hierarquias de herança.

     class Nigeria():
        def culture(self):
            print("Nigeria's culture")

    class Africa():
       def culture(self):
           print("Africa's culture")

    Veja o que acontece quando você cria uma instância da classe Lagos e chama o método culture:

      Como funciona um certificado X.509?
  • Python começa procurando o método de cultura na própria classe Lagos. Se encontrar, ele chama o método. Caso contrário, passa para a etapa dois.
  • Se não encontrar o método de cultura na classe Lagos, o Python examinará as classes base na ordem em que aparecem na definição da classe. Neste caso, Lagos herda primeiro de África e depois da Nigéria. Portanto, Python procurará primeiro o método de cultura na África.
  • Se não encontrar o método de cultura na classe África, o Python procurará na classe Nigéria. Esse comportamento continua até atingir o final da hierarquia e gera um erro se não conseguir encontrar o método em nenhuma das superclasses.
  • A saída mostra a Ordem de Resolução do Método de Lagos, começando da esquerda para a direita.

    Armadilhas comuns e práticas recomendadas

    Ao trabalhar com super(), existem algumas armadilhas comuns a serem evitadas.

  • Esteja atento à Ordem de Resolução do Método, especialmente em cenários de herança múltipla. Se você precisar usar herança múltipla complexa, você deve estar familiarizado com o Algoritmo de linearização C3 que o Python usa para determinar o MRO.
  • Evite dependências circulares na hierarquia de classes, que podem levar a um comportamento imprevisível.
  • Documente seu código de forma clara, especialmente ao usar super() em hierarquias de classes complexas, para torná-lo mais compreensível para outros desenvolvedores.
  • Use super() da maneira certa

    A função super() do Python é um recurso poderoso quando você trabalha com herança e substituição de métodos. Compreender como super() funciona e seguir as práticas recomendadas permitirá que você crie um código mais sustentável e eficiente em seus projetos Python.