Módulo 12 - Decoradores
Preservando a identidade com functools.wraps
10 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Observar que a função decorada passa a mostrar wrapper no lugar do nome original.
- Entender por que isso atrapalha depuração, ajuda e documentação.
- Aplicar @functools.wraps(func) sobre o wrapper para preservar a identidade.
- Adotar functools.wraps como parte fixa de todo decorador que você escrever.
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: Preservando a identidade com functools.wraps.
Os objetivos desta aula. Observar que a função decorada passa a mostrar wrapper no lugar do nome original. Entender por que isso atrapalha depuração, ajuda e documentação. Aplicar @functools.wraps(func) sobre o wrapper para preservar a identidade. Adotar functools.wraps como parte fixa de todo decorador que você escrever.
Veja o essencial, parte por parte.
O problema e a cura, em resumo. Ao decorar, o nome real vira wrapper e a docstring original se perde.
A cura de uma linha. Comece todo decorador importando functools no topo do arquivo.
Fechando a boa prática. A partir daqui, o modelo mental do decorador completo tem três camadas: a função externa recebe func, o wrapper aceita *args e **kwargs e devolve o resultado com return, e o wrapper leva @functools.wraps(func) por cima para preservar a identidade.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
O problema e a cura, em resumo
Nosso decorador já aceita qualquer função e devolve o resultado. Mas ele criou um problema discreto. Como o nome da função passou a apontar para o wrapper, quando você pergunta o nome ou a documentação da função decorada, o Python responde com os dados do wrapper, não da função original. Na prática, uma função somar decorada passa a se chamar wrapper e perde a docstring que você escreveu. Isso parece detalhe, mas incomoda muito na hora de depurar um erro, gerar documentação automática ou usar o help() no terminal.
def com_moldura(func):
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@com_moldura
def somar(a, b):
"Soma dois números e devolve o total."
return a + b
print(somar.__name__) # wrapper (deveria ser somar)
print(somar.__doc__) # None (a docstring sumiu)Sem cuidado, a função decorada esquece o próprio nome e a própria documentação.
A cura de uma linha
A biblioteca padrão já resolveu isso para você, no módulo functools. Ele traz um decorador chamado wraps, feito exatamente para ser aplicado sobre o wrapper. O que o functools.wraps faz é copiar para o wrapper os metadados da função original: o nome, a docstring, o módulo e outros atributos internos. Você o usa como @functools.wraps(func) na linha imediatamente acima da definição do wrapper, passando a função original que está sendo decorada. Repare que aqui aparece um decorador decorando o próprio wrapper de outro decorador, o que é uma boa prova de que você entendeu a mecânica.
import functools
def com_moldura(func):
@functools.wraps(func) # copia nome e docstring de func
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@com_moldura
def somar(a, b):
"Soma dois números e devolve o total."
return a + b
print(somar.__name__) # somar
print(somar.__doc__) # Soma dois números e devolve o total.Com @functools.wraps(func), a função decorada mantém nome e docstring reais.
Fechando a boa prática
A partir daqui, o modelo mental do decorador completo tem três camadas: a função externa recebe func, o wrapper aceita *args e **kwargs e devolve o resultado com return, e o wrapper leva @functools.wraps(func) por cima para preservar a identidade. Esse é o esqueleto que você vai repetir em qualquer decorador sério. O wraps não muda o que o decorador faz; ele apenas evita que a função decorada minta sobre quem é. É barato, cabe em uma linha e evita dores de cabeça futuras com depuração e documentação. Na próxima aula, colocamos tudo isso em prática com casos de uso reais.
Teste rápido
Para que serve aplicar @functools.wraps(func) sobre o wrapper?
Perguntas frequentes
- O que quebra se eu não usar functools.wraps?
- Nada trava de imediato, mas a função decorada passa a se identificar como wrapper e perde a docstring. Isso atrapalha mensagens de erro, o help() no terminal, ferramentas de documentação automática e qualquer código que inspecione o nome ou a assinatura da função. É um problema silencioso, por isso o wraps é considerado boa prática.
- Onde exatamente coloco o @functools.wraps(func)?
- Na linha imediatamente acima da def wrapper, dentro do decorador, passando a função original como argumento: @functools.wraps(func). Ele decora o wrapper, copiando para ele os metadados de func. Não confunda com a linha @seu_decorador, que fica sobre a função que você quer decorar no uso.
- Preciso importar alguma coisa?
- Sim, o functools faz parte da biblioteca padrão, então basta import functools no topo do arquivo, sem instalar nada. Você também pode escrever from functools import wraps e usar apenas @wraps(func). Os dois estilos funcionam igual.
- O functools.wraps é um decorador também?
- É. Ele é um decorador que você aplica sobre o wrapper. Por isso a linha aparece com o símbolo @ e recebe a função original como argumento. Ver um decorador sendo usado dentro de outro decorador é um bom sinal de que a mecânica ficou clara para você.
- Ele copia a assinatura de argumentos também?
- Ele copia metadados como nome, docstring, módulo e o dicionário de atributos, e ajusta o __wrapped__ apontando para a função original. Ferramentas modernas de inspeção conseguem, a partir disso, recuperar a assinatura real. Para o dia a dia, o ganho principal é ter nome e docstring corretos de volta.
- Vale usar wraps mesmo em decorador simples?
- Vale. O custo é uma linha e o benefício é a função decorada nunca mentir sobre a própria identidade. Adotar functools.wraps como parte fixa do formato do decorador evita que você esqueça justamente quando o metadado correto fizer falta, no meio de uma depuração.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.