Decoradores em Python são uma ferramenta poderosa para modificar o comportamento de funções ou classes. O símbolo @ é usado para aplicar um decorador de forma sintática.
Quando você escreve:
@decorador2
@decorador1
def minha_funcao(arg1, arg2):
pass
Isso é equivalente a:
def minha_funcao(arg1, arg2):
pass
minha_funcao = decorador2(decorador1(minha_funcao))
A seguir, exploramos diversos casos de uso com exemplos práticos.
1. Registrar uma Função para Execução ao Sair
Este decorador registra uma função para ser chamada quando o programa termina, usando o módulo atexit.
import atexit
def registrar_saida(func):
atexit.register(func)
return func
@registrar_saida
def ao_sair():
print("Executando limpeza antes de sair...")
2. Implementar uma Classe Singleton
O decorador singleton garante que apenas uma instância da classe seja criada, armazenando-a em um cache.
def singleton(cls):
cache = {}
def obter_instancia():
if cls not in cache:
cache[cls] = cls()
return cache[cls]
return obter_instancia
@singleton
class MinhaClasse:
def __init__(self):
self.dado = "Única instância"
3. Adicionar Atributos a uma Função
Este decorador permite definir atributos personalizados em funções, como versão ou autor.
def adicionar_atributos(**atributos):
def decorador(func):
for chave, valor in atributos.items():
setattr(func, chave, valor)
return func
return decorador
@adicionar_atributos(versao="1.0", autor="Ana Silva")
def meu_metodo():
pass
print(meu_metodo.versao) # Saída: 1.0
4. Verificar Tipos de Argumentos e Retorno
Decoradores para validar os tipos dos argumentos e do valor de retorno de uma função.
def aceita_tipos(*tipos):
def verificar(func):
def nova_func(*args, **kwargs):
for arg, tipo in zip(args, tipos):
if not isinstance(arg, tipo):
raise TypeError(f"Argumento {arg} não é do tipo {tipo}")
return func(*args, **kwargs)
nova_func.__name__ = func.__name__
return nova_func
return verificar
def retorna_tipo(tipo_retorno):
def verificar(func):
def nova_func(*args, **kwargs):
resultado = func(*args, **kwargs)
if not isinstance(resultado, tipo_retorno):
raise TypeError(f"Retorno {resultado} não é do tipo {tipo_retorno}")
return resultado
nova_func.__name__ = func.__name__
return nova_func
return verificar
@aceita_tipos(int, float)
@retorna_tipo(float)
def multiplicar(a, b):
return a * b
5. Declarar Conformidade com Interfaces
Este exemplo demonstra como usar decoradores para indicarr que uma classe implementa uma interface específica.
class InterfaceExemplo:
pass
def implementa(*interfaces):
def decorador(classe):
# Lógica para registrar conformidade (exemplo simplificado)
classe._interfaces = interfaces
return classe
return decorador
@implementa(InterfaceExemplo)
class MinhaClasse2:
def metodo(self):
pass