Como criar e usar decoradores em Python

Aprenda como escrever e aplicar decoradores em Python. Domine funções de encapsulamento, modificando comportamento, manipulando argumentos e preservando metadados com encapsulamentos.

Experimente esta solução no Editor

Visão geral

Decoradores são um dos recursos de sintaxe mais elegantes e poderosos do Python, permitindo modificar o comportamento de uma função ou classe sem alterar permanentemente seu código. Eles são amplamente usados ​​para questões transversais, como registrar tempos de execução, impor autenticação do usuário, armazenar resultados em cache (memoização) e auditar endpoints de API.

Nos bastidores, um decorador é uma função de ordem superior que recebe outra função como argumento, define uma função wrapper aninhada que injeta alguma lógica personalizada e retorna essa função wrapper. Python fornece uma sintaxe abreviada limpa usando o símbolo `@` para aplicar decoradores às funções, tornando-as visualmente elegantes.

Ao escrever decoradores, você normalmente desejará que a função decorada suporte qualquer número de argumentos posicionais e de palavras-chave. Você pode conseguir isso projetando a função wrapper aninhada para aceitar `*args` e `**kwargs` e passá-los para a função de destino. Além disso, você deve usar `functools.wraps` na função wrapper para preservar a documentação da função original e os metadados de nome.

Saída de código e execução

Este script demonstra como escrever um decorador de registro e agrupar uma função para inspecionar entradas, saídas e metadados.

decorators_tutorial.py
Experimente no Editor
from functools import wraps

# 1. Defining a decorator
def log_execution(func):
    @wraps(func) # Preserves original function metadata
    def wrapper(*args, **kwargs):
        print(f"[Log] Calling function: {func.__name__} with args: {args}")
        result = func(*args, **kwargs)
        print(f"[Log] Finished {func.__name__}. Result: {result}")
        return result
    return wrapper

# 2. Applying the decorator using @ syntax
@log_execution
def add_numbers(a, b):
    """Adds two numbers and returns the sum."""
    return a + b

# 3. Invoking the decorated function
sum_result = add_numbers(15, 25)
print("Sum Result:", sum_result)

# Verifying metadata preservation
print("Docstring preserved:", add_numbers.__doc__)
Saída terminal
[Log] Calling function: add_numbers with args: (15, 25)
[Log] Finished add_numbers. Result: 40
Sum Result: 40
Docstring preserved: Adds two numbers and returns the sum.

Implementação passo a passo

  • Defina uma função de decorador externo que receba a função de destino como argumento.
  • Importe e aplique @functools.wraps(func) em sua função wrapper aninhada para proteger os metadados originais.
  • Implemente wrapper(*args, **kwargs) para capturar variáveis de entrada, injetar lógica e invocar a função de destino.
  • Retorne o objeto de função wrapper do bloco de cabeçalho do decorador.
  • Aplique o decorador usando @decorator_name diretamente acima da assinatura da função alvo.

Perguntas frequentes

Por que @functools.wraps é necessário dentro de decoradores?

Sem wraps, a função decorada perde sua identidade original (seus atributos __name__ e __doc__ são substituídos pelos da função wrapper aninhada), o que dificulta a depuração e a introspecção do código.

Posso aplicar vários decoradores a uma única função?

Sim! Você pode encadear decoradores empilhando várias @ linhas. Python os aplica de baixo para cima (o mais próximo da definição da função é executado primeiro).

Tópicos Relacionados

Recursos Python recomendados

Expanda seu conhecimento com tutoriais interativos relacionados, folhas de dicas e comparações de código.