Módulo 12 - Decoradores

O caminho até o decorador

11 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Relembrar que em Python uma função é um objeto que pode ser passado e devolvido.
  • Entender closure: uma função interna que lembra as variáveis da função externa.
  • Construir um decorador manualmente, sem usar o símbolo @.
  • Enxergar que decorar é envolver uma função em outra que adiciona comportamento.

O que é um decorador, em uma ideia

Decorador tem fama de assunto difícil, e quase sempre isso vem de começar pelo símbolo @ antes de entender a ideia por baixo. Vamos pelo caminho contrário. Um decorador não é um recurso mágico da linguagem; é um jeito de usar duas coisas que você já conhece. A primeira é que, em Python, uma função é um objeto como outro qualquer: você pode guardá-la numa variável, colocá-la numa lista, passá-la para outra função e devolvê-la de dentro de uma função. A segunda é a closure, uma função escrita dentro de outra que lembra das variáveis de fora. Junte as duas e o decorador aparece sozinho.

def saudacao():
    return "Olá!"

# Uma função pode ir para uma variável, sem parênteses.
apontador = saudacao
print(apontador())     # Olá!

# E pode ser passada como argumento para outra função.
def executar_duas_vezes(func):
    return func() + " " + func()

print(executar_duas_vezes(saudacao))   # Olá! Olá!

Sem parênteses, saudacao é o objeto função; com parênteses, você a executa.

Closure, a peça que faltava

A parte que falta é conseguir devolver uma função nova. Para isso, escrevemos uma função dentro de outra. A função interna usa a variável da externa (a função recebida) e é devolvida para ser chamada depois. Como ela lembra dessa variável mesmo depois que a externa terminou, temos uma closure. Repare que devolvemos o objeto função, sem parênteses; quem recebeu decide quando chamar. Esse é o esqueleto exato de todo decorador que você vai escrever pelo resto do curso.

def com_moldura(func):
    def wrapper():
        print("=== inicio ===")
        func()
        print("=== fim ===")
    return wrapper           # devolve a função interna, sem chamar

def dizer_ola():
    print("Olá, mundo")

# Envolvemos dizer_ola na moldura e guardamos o resultado.
decorada = com_moldura(dizer_ola)
decorada()
# === inicio ===
# Olá, mundo
# === fim ===

com_moldura recebe uma função e devolve wrapper, que a chama entre duas linhas.

Leia esse exemplo com calma, porque ele é o coração do módulo. A função com_moldura é o decorador. Ela não faz nada sozinha: recebe uma função qualquer no parâmetro func, define uma função interna wrapper que chama func no meio de duas mensagens, e devolve wrapper. Quando escrevemos decorada = com_moldura(dizer_ola), a variável decorada passa a apontar para o wrapper, que por dentro lembra qual era a func original. Chamar decorada() executa a versão envolvida. Note que dizer_ola em nada foi alterada; ela continua intacta. O que ganhamos foi uma nova função com comportamento a mais ao redor dela.

Sem decorador

  • Copiar as linhas de moldura dentro de cada função
  • Repetir o mesmo trecho em vários lugares
  • Mudar a moldura pede editar função por função
  • A função mistura o que faz com o extra

Com decorador

  • Escrever a moldura uma vez, no wrapper
  • Reaproveitar em qualquer função
  • Mudar a moldura em um lugar só
  • A função original fica limpa e focada

Fixando a ideia central

Antes de conhecer o atalho do símbolo @ na próxima aula, garanta que a ideia base está firme. Um decorador é, em uma frase, uma função que recebe uma função e devolve uma função. A função devolvida (o wrapper) chama a original e acrescenta comportamento antes, depois, ou nos dois momentos. Nada nisso exige sintaxe nova; é tudo função de primeira classe mais closure, dois assuntos que você já viu. Se esse esqueleto ficou claro, o resto do módulo é aprender formas mais elegantes e completas de escrever a mesma coisa.

Teste rápido

O que a função com_moldura(func) devolve?

Perguntas frequentes

Preciso entender closure antes de decoradores?
Ajuda muito. Um decorador é uma closure: a função interna wrapper lembra da função original recebida no parâmetro. Se a ideia de uma função interna que guarda variáveis da externa ainda confunde, vale revisar o módulo de funções avançadas antes de seguir para o símbolo @.
Por que passamos a função sem os parênteses?
Sem parênteses, você passa o objeto função; com parênteses, você executa a função e passa o resultado. O decorador precisa receber a função em si para poder chamá-la mais tarde, dentro do wrapper. Por isso escrevemos com_moldura(dizer_ola), não com_moldura(dizer_ola()).
O decorador altera a função original?
Não. A função original continua intacta. O decorador cria uma função nova (o wrapper) que envolve a original e adiciona comportamento. O que muda é para onde o nome passa a apontar quando você reatribui, algo que a próxima aula formaliza com o símbolo @.
Isso é a mesma coisa que decorador do padrão de projeto?
A ideia é parecida (envolver algo para acrescentar comportamento), mas o decorador do Python é um recurso concreto da linguagem, com sintaxe própria. Neste curso tratamos do decorador do Python, aquele que você aplica com o símbolo @ sobre uma função.
Todo decorador precisa de uma função interna?
No padrão que você vai usar quase sempre, sim: a função externa recebe a função a decorar e a interna (o wrapper) faz o trabalho de envolvê-la. Existem variações mais avançadas, mas comece dominando esse formato de função dentro de função, que resolve a grande maioria dos casos.
Function é objeto mesmo em Python?
Sim. Funções são objetos de primeira classe: você pode guardá-las em variáveis, colocá-las em listas, passá-las como argumento e devolvê-las de outra função. Toda a mecânica de decoradores depende disso, e é por isso que a aula começa reforçando esse ponto.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.