Módulo 5 - Decoradores avançados
Decorar uma classe inteira
9 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Entender que um decorador de classe recebe e devolve a própria classe.
- Criar um decorador que acrescenta um método ou atributo a uma classe.
- Usar um decorador de classe para registrar classes automaticamente.
- Reconhecer @dataclass como decorador de classe da biblioteca padrão.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Decorar uma classe inteira.
Os objetivos desta aula. Entender que um decorador de classe recebe e devolve a própria classe. Criar um decorador que acrescenta um método ou atributo a uma classe. Usar um decorador de classe para registrar classes automaticamente. Reconhecer @dataclass como decorador de classe da biblioteca padrão.
Veja o essencial, parte por parte.
Uma classe também é um objeto. Um decorador de classe recebe a classe como argumento e devolve uma classe.
Registro automático de classes. Pense num evento em que cada convidado assina a lista ao entrar.
O dataclass, exemplo oficial. Você não precisa criar decoradores de classe todo dia, mas encontra um dos mais úteis da linguagem com frequência: o @dataclass.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
Uma classe também é um objeto
No Python, uma classe também é um objeto, criado quando o interpretador executa o bloco class. Isso significa que você pode passar uma classe para uma função, guardá-la em uma variável e, claro, decorá-la. Um decorador de classe funciona igual ao de função: ele recebe algo (agora a classe), faz o que precisa e devolve algo (a classe, modificada ou não). A sintaxe com arroba é idêntica, só que aplicada em cima de um class em vez de um def.
def com_descricao(cls):
def descrever(self):
return f"{cls.__name__} com atributos {list(self.__dict__)}"
cls.descrever = descrever
return cls
@com_descricao
class Produto:
def __init__(self, nome, preco):
self.nome = nome
self.preco = preco
p = Produto("Cafe", 20)
print(p.descrever()) # Produto com atributos ['nome', 'preco']O decorador recebe a classe, acrescenta um método descrever e devolve a classe.
Repare no essencial: com_descricao recebe cls, a classe, define uma função descrever, gruda essa função na classe com cls.descrever = descrever e devolve cls. A partir daí, toda instância de Produto tem o método descrever, mesmo que ele não apareça no corpo da classe. Esse padrão de acrescentar comportamento de fora é útil para aplicar a mesma capacidade a várias classes sem repetir código nem recorrer a herança.
Registro automático de classes
Um uso muito comum de decorador de classe é o registro automático. Imagine um sistema de plugins ou de tipos de relatório: cada nova classe precisa ficar disponível em um catálogo central para ser encontrada pelo nome. Em vez de manter uma lista à mão, que sempre esquecem de atualizar, um decorador cadastra a classe no momento em que ela é definida. O código fica declarativo: basta anotar a classe com @registrar e ela aparece no catálogo.
RELATORIOS = {}
def registrar_relatorio(cls):
RELATORIOS[cls.tipo] = cls
return cls
@registrar_relatorio
class RelatorioPDF:
tipo = "pdf"
@registrar_relatorio
class RelatorioCSV:
tipo = "csv"
print(RELATORIOS) # {'pdf': RelatorioPDF, 'csv': RelatorioCSV}
escolhida = RELATORIOS["csv"]
print(escolhida.__name__) # RelatorioCSVCada classe se cadastra sozinha no dicionário RELATORIOS ao ser definida.
O dataclass, exemplo oficial
Você não precisa criar decoradores de classe todo dia, mas encontra um dos mais úteis da linguagem com frequência: o @dataclass. Ele é um decorador de classe da biblioteca padrão que, ao ler os atributos anotados da sua classe, gera automaticamente o __init__, o __repr__ e o __eq__, entre outros. Ou seja, ele modifica a classe acrescentando métodos, exatamente o que você fez à mão nas seções anteriores, só que de forma muito mais completa. Vê-lo como decorador de classe desmistifica a mágica.
from dataclasses import dataclass
@dataclass
class Ponto:
x: int
y: int
# O @dataclass gerou __init__, __repr__ e __eq__ automaticamente
p1 = Ponto(1, 2)
p2 = Ponto(1, 2)
print(p1) # Ponto(x=1, y=2) <- __repr__ gerado
print(p1 == p2) # True <- __eq__ gerado@dataclass é um decorador de classe que gera métodos a partir dos atributos anotados.
O dataclass tem um módulo inteiro dedicado a ele mais adiante no curso, então aqui basta a ideia: é um decorador de classe. Quando você entende que decorar uma classe é só receber o objeto classe, mexer nele e devolvê-lo, deixa de haver mágica. A mesma técnica que grudou um método descrever no Produto é a que, muito mais elaborada, gera o __init__ do dataclass. Reconhecer o padrão é o que permite ler e escrever esse tipo de código com confiança.
Teste rápido
O que um decorador de classe recebe como argumento?
Perguntas frequentes
- Qual a diferença entre decorar uma função e decorar uma classe?
- A mecânica é a mesma: o decorador recebe o objeto (função ou classe) e devolve algo no lugar. A diferença é o que você faz dentro. Num decorador de função você costuma envolver a chamada com um wrapper; num decorador de classe você costuma modificar a classe em si, adicionando métodos ou atributos ou registrando-a em algum lugar.
- Decorador de classe substitui herança?
- Não substitui, complementa. A herança é ótima para relações do tipo é um. O decorador de classe é melhor quando você quer aplicar uma capacidade transversal a várias classes sem criar uma base comum artificial, como registrar todas num catálogo. Cada ferramenta tem seu momento; muitas vezes elas convivem.
- Preciso sempre devolver a classe no fim do decorador?
- Sim, praticamente sempre. Se você não devolver a classe, o nome passa a apontar para o que o decorador retornou (por exemplo None), e a classe some. O padrão seguro é modificar a classe recebida e terminar com return cls. Só em casos avançados você devolve uma classe diferente de propósito.
- O @dataclass é mesmo um decorador de classe comum?
- É, embora muito sofisticado. Ele recebe a classe, lê os atributos anotados e gera métodos como __init__, __repr__ e __eq__, devolvendo a classe modificada. A ideia central é idêntica à de um decorador de classe caseiro; o que muda é a quantidade de trabalho que ele faz por você. Há um módulo inteiro sobre ele mais à frente.
- Posso combinar um decorador de classe com functools.wraps?
- O functools.wraps foi pensado para wrappers de função, então não se aplica da mesma forma a classes. Num decorador de classe você geralmente modifica e devolve a própria classe, que já preserva o nome e a identidade. Se você envolver métodos individuais dentro do decorador de classe, aí sim usa wraps em cada wrapper de método.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.