Implementação e Uso de Decoradores em Python

Decoradores em Python são ferramentas poderosas que permitem modificar ou estender o comportamento de funções ou classes sem alterar permanentemente seu código-fonte. Estruturalmente, um decorador é uma função que recebe outra função como argumento e retorna uma nova função com funcionalidades adicionadas, utilizando conceitos de clausuras (closures) e escopos de nomes.

Estrutura Básica de um Decorador

A forma mais simples de um decorador envolve envolver uma função original dentro de uma função interna que executa lógica adicional antes ou depois da chamada principal.

import time

def monitorar_tempo(funcao_alvo):
    def wrapper():
        inicio = time.time()
        funcao_alvo()
        fim = time.time()
        print(f"Tempo de execução: {fim - inicio:.4f} segundos")
    return wrapper

def carregar_sistema():
    time.sleep(1.5)
    print("Sistema carregado com sucesso.")

# Aplicando manualmente
sistema_com_timer = monitorar_tempo(carregar_sistema)
sistema_com_timer()

Suporte a Argumentos e Retornos

Para que um decorador seja genérico e funcione com qualquer função, ele deve ser capaz de aceitar argumentos variáveis (*args e **kwargs) e capturar o valor de retorno da função original.

import time

def cronometro(funcao):
    def executor(*args, **kwargs):
        print(f"Iniciando: {funcao.__name__}")
        instante_inicial = time.time()
        
        # Captura o retorno da função original
        resultado = funcao(*args, **kwargs)
        
        instante_final = time.time()
        print(f"Finalizado em: {instante_final - instante_inicial:.4f}s")
        return resultado
    return executor

def saudar_usuario(nome):
    time.sleep(1)
    return f"Olá, {nome}! Bem-vindo ao portal."

# Aplicando o decorador com suporte a argumentos
saudar_decorado = cronometro(saudar_usuario)
mensagem = saudar_decorado("Gabriel")
print(mensagem)

Açúcar Sintático com @

O Python oferece uma sintaxe simplificada para aplicar decoradores utilizando o símbolo @ acima da definição da função. Isso substitui a necessidade de reatribuir a função manualmente.

def verificar_status(funcao):
    def wrapper(*args, **kwargs):
        print("Verificando permissões de acesso...")
        return funcao(*args, **kwargs)
    return wrapper

@verificar_status
def deletar_registro(id_registro):
    print(f"Registro {id_registro} removido.")

deletar_registro(505)

Empilhamento de Decoradores

É possível aplicar múltiplos decoradores a uma única função. Eles são processados de baixo para cima (do mais próximo da função para o mais distante).

def negrito(funcao):
    def wrapper():
        return f"<b>{funcao()}</b>"
    return wrapper

def italico(funcao):
    def wrapper():
        return f"<i>{funcao()}</i>"
    return wrapper

@negrito
@italico
def formatar_texto():
    return "Texto Formatado"

print(formatar_texto()) # Saída: <b><i>Texto Formatado</i></b>

Decoradores com Parâmetros Próprios

Quando o próprio decorador precisa de argumentos para configurar seu comportamento, é necessária uma camada aidcional de funções (uma função que retorna o decorador).

def nivel_acesso(nivel):
    def decorador_real(funcao_alvo):
        def wrapper(*args, **kwargs):
            if nivel == "admin":
                print("Acesso total concedido.")
                return funcao_alvo(*args, **kwargs)
            elif nivel == "user":
                print("Acesso limitado concedido.")
                return funcao_alvo(*args, **kwargs)
            else:
                print("Acesso negado.")
        return wrapper
    return decorador_real

@nivel_acesso(nivel="admin")
def painel_controle():
    print("Exibindo configurações do servidor.")

painel_controle()

Template Universal de Decoradores

Para a maioria dos casos de uso em desenvolvimento de software, a estrutura a seguir serve como base robusta:

def decorador_padrao(funcao):
    def wrapper(*args, **kwargs):
        # Lógica antes da execução
        resultado = funcao(*args, **kwargs)
        # Lógica após a execução
        return resultado
    return wrapper

Tags: Python decoradores closures programacao-funcional

Publicado em 6-7 23:23 por Thomas