Entendendo a função super() do Python

Ana Maria Gomes
8 minutos de leitura

Conteúdos do tutorial

Ao se aprofundar no mundo do Python, especialmente na programação orientada a objetos, você frequentemente se deparará com a função super(). Essa função é uma parte vital da herança de classes e desempenha um papel crucial na inicialização de métodos herdados dentro de classes derivadas. Mas por que exatamente usamos a função super() do Python, e como ela difere de chamar diretamente o método __init__ de uma classe base? Vamos explorar essas questões em detalhes.

O que a função super() do Python faz?

Quando criamos uma classe derivada (“filha”) a partir de uma classe base (“pai”) em Python, os métodos e atributos da classe derivada acabam por sobrescrever os métodos da classe base de mesmo nome. No exemplo abaixo, note que a classe Derivada não consegue acessar o método Base.bar(), porque ela possui uma nova implementação do mesmo método:

class Base():
    def foo(self):
        print('Base chamou método foo')

    def bar(self):
        print('Base chamou método bar')


class Derivada(Base):
    def bar(self):
        print('Derivada chamou método bar')


d = Derivada()
d.foo()  # Output: Base chamou método foo
d.bar()  # Output: Derivada chamou método bar

Este é o comportamento esperado, afinal uma classe derivada pode muitas vezes querer usar uma implementação diferente de um método da classe base. Dito isso, e se quiséssemos acessar o método Base.bar() a partir da instância de Derivada()? É aí que entra a função super() do Python: ela nos dá uma referência à classe imediatamente acima da classe em que é chamada e, por consequência, concede acesso direto a todos os seus métodos:

class Base():
    def foo(self):
        print('Base chamou método foo')

    def bar(self):
        print('Base chamou método bar')


class Derivada(Base):
    def bar(self):
        print('Derivada chamou método bar')
    
    def bar_base(self):
        return super().bar()


d = Derivada()
d.foo()  # Output: Base chamou método foo
d.bar()  # Output: Derivada chamou método bar
d.bar_base()  # Output: Base chamou método bar

No exemplo acima, o método Derivada.bar_base usa a função super() para acessar o método Base.bar.

O Papel da Função super() do Python na Herança de Classes

Como vimos anteriormente, a função super() do Python é usada para dar acesso a métodos de uma classe herdada sem nomear explicitamente a classe base. Isso é particularmente útil porque, se trocarmos a classe base, o código será capaz de automaticamente acessar os métodos da nova base.

Considere o seguinte exemplo:

class Base:
    def __init__(self):
        print("Base inicializada")


class Derivada1(Base):
    def __init__(self):
        Base.__init__(self)


class Derivada2(Base):
    def __init__(self):
        super().__init__()


d1 = Derivada1()  # output: Base inicializada
d2 = Derivada2()  # output: Base inicializada

Quando instanciamos objetos das classes Derivada1() e Derivada2(), ambos imprimirão “Base inicializada”, uma vez que ambos acessam e executam o método Base.__init__() dentro do seu próprio método __init__(). No entanto, como veremos a seguir, a maneira como eles acessam o método Base.__init__() é diferente.

Em Derivada1, chamamos diretamente Base.__init__(self), o que é simples, mas não flexível. Se decidirmos mudar a classe base ou introduzir herança múltipla, precisaríamos atualizar a referência à classe base em todos os lugares onde ela é chamada explicitamente.

Por outro lado, Derivada2 usa super().__init__(), que não requer que o nome da classe base seja explicitamente declarado. Isso não é apenas mais limpo, mas também mais fácil de manter, especialmente ao lidar com herança múltipla.

A Função super() com Hierarquias de Classes Complexas

O verdadeiro poder de super() é revelado em estruturas de herança complexas. Ele usa a ordem de resolução de métodos (MRO, sigla do inglês method resolution order) para determinar a próxima classe a procurar pelo método __init__. Isso garante que todos os métodos __init__ na hierarquia de herança sejam chamados na ordem e quantidade corretos, o que é essencial para inicializar todos os aspectos de um objeto adequadamente.

Um Exemplo Prático

Veja o que acontece com uma classe contendo herança múltipla — neste exemplo, a classe User representada pelo diagrama abaixo:

Abaixo, a mesma estrutura reproduzida em código:

class Base:
    def __init__(self):
        print("Base inicializada")

class ChildA(Base):
    def __init__(self):
        print("ChildA inicializada")
        super().__init__()

class ChildB(Base):
    def __init__(self):
        print("ChildB inicializada")
        super().__init__()

class User(ChildA, ChildB):
    def __init__(self):
        print("User inicializada")
        super().__init__()


user = User()

Quando criamos uma instância de User, as respectivas chamadas a super().__init__ são feitas respeitando a hierarquia de classes. A saída é:

User inicializada
ChildA inicializada
ChildB inicializada
Base inicializada

Isso demonstra que o método super().__init__ dentro da classe User chama corretamente os métodos __init__ de ChildA, ChildB e Base na ordem certa. Além disso, embora ambos ChildA e ChildB acabem chamando Base.__init__ através de super(), veja que este método executa apenas uma vez. Isso tudo é fruto da praticidade da função super() do Python!

Resumo

Em resumo, a função super() do Python é uma função que permite uma maneira limpa e fácil de manter para chamar métodos de classes pai no Python, especialmente em hierarquias de herança complexas. Ela aproveita a ordem de resolução de métodos para garantir que todas as classes pai sejam inicializadas corretamente. Com o Python 3, super() tornou-se ainda mais amigável, permitindo chamadas sem argumentos. Lembre-se de evitar usar super(self.__class__, self).__init__() pois isso pode levar a problemas de recursão. Em vez disso, aproveite a simplicidade e o poder de super() para escrever códigos de Python orientados a objetos mais fáceis de manter e livres de erros.

Inscreva-se gratuitamente e fique atualizado

Receba toda semana um resumo dos principais conteúdos da Asimov direto no seu e-mail. 100% livre de spam.

Áreas de interesse: