O que são decoradores em Python
Se você programa em Python há mais de uma semana, certamente já viu o símbolo @ acima de uma função. Isso é um decorador — uma ferramenta poderosa e elegante de programação.
Decoradores em Python permitem "encapsular" uma função dentro de outra. Eles modificam ou estendem o comportamento de uma função sem alterar seu código original. Decoradores são usados em toda parte: em Flask, Django, FastAPI, pytest, e até mesmo na biblioteca padrão do Python.
Como os decoradores funcionam
Fundamentos dos decoradores
Um decorador é uma função que recebe outra função como argumento e retorna uma nova função (ou a função original modificada).
def decorator(func):
def wrapper():
print("Antes da chamada")
func()
print("Depois da chamada")
return wrapper
@decorator
def say_hello():
print("Olá!")
say_hello()
Resultado da execução:
Antes da chamada
Olá!
Depois da chamada
O símbolo @decorator é um açúcar sintático para a escrita:
say_hello = decorator(say_hello)
Funcionamento interno dos decoradores
Para entender decoradores em Python, é preciso conhecer alguns conceitos-chave:
- Em Python, funções são objetos de primeira classe
- Funções podem ser passadas como argumentos para outras funções
- É possível definir funções dentro de outras funções
- Existe o mecanismo de closures (encerramentos)
Modelo universal de decorador
O modelo mínimo de um decorador é o seguinte:
def decorator(func):
def wrapper(*args, **kwargs):
# Ações antes da execução da função
result = func(*args, **kwargs)
# Ações depois da execução da função
return result
return wrapper
Exemplos práticos de decoradores
Decorador para medir tempo de execução
import time
def timing(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
execution_time = time.time() - start
print(f"{func.__name__} levou {execution_time:.4f} segundos")
return result
return wrapper
@timing
def slow_func():
time.sleep(1)
return "Operação concluída"
slow_func()
Este decorador é útil para analisar o desempenho de funções e otimizar seu código.
Decorador de verificação de autorização
def require_admin(func):
def wrapper(user, *args, **kwargs):
if user != "admin":
raise PermissionError("Acesso negado")
return func(user, *args, **kwargs)
return wrapper
@require_admin
def delete_database(user):
print("Banco de dados excluído!")
return True
delete_database("admin") # Execução bem-sucedida
Esse decorador garante a segurança da aplicação, controlando o acesso a funções críticas.
Decorador de logging
import logging
from functools import wraps
def log_calls(func):
@wraps(func)
def wrapper(*args, **kwargs):
logging.info(f"Chamada da função {func.__name__} com argumentos {args}, {kwargs}")
try:
result = func(*args, **kwargs)
logging.info(f"Função {func.__name__} executada com sucesso")
return result
except Exception as e:
logging.error(f"Erro na função {func.__name__}: {e}")
raise
return wrapper
Decoradores com argumentos
Criando uma fábrica de decoradores
Quando um decorador precisa receber parâmetros, cria-se uma fábrica de decoradores:
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
results = []