Python decorator
Python decorator (decorador) é um padrão de design que permite a adição de novas funcionalidades a um objeto existente sem modificar sua estrutura. Os decoradores são tipicamente funções aplicadas a funções. Eles são utilizados para aprimorar o comportamento de funções com recursos adicionais. Alguns casos de uso comuns para decoradores incluem temporização, cache, registro em log, autenticação e rastreamento de desempenho.
A base para o comportamento de um Python decorator reside no fato das funções serem objetos de primeira classe. Isso significa que elas possuem suporte para serem passadas como argumentos, retornadas de uma função, modificadas e atribuídas a uma variável. Essas propriedades permitem que as funções sejam tratadas como qualquer outro objeto em Python, possibilitando maior flexibilidade na programação. As mesmas propriedades também são essenciais para entender a criação e uso de decoradores Python. Portanto, a seguir, iremos abordá-las passo a passo.
Funções Atribuídas a Variáveis
Em Python, funções podem ser diretamente atribuídas a variáveis como ilustrado no exemplo abaixo. Uma vez que uma função é atribuída a uma variável, ela é executada quando a variável é chamada.
# define função
def minha_func(numero):
return numero * 2
# Atribui a função a uma variável
minha_var = minha_func
print(minha_var(20)) # imprime variável
# resultado: 40
Funções definidas dentro de outras funções
O Python também permite que funções sejam definidas dentro de outras funções. Isso é ilustrado no exemplo a seguir.
# Define uma função dentro de outra função
def minha_outra_func(numero):
def minha_func(numero):
return numero * 2
res = minha_func(numero)
return res
print(minha_outra_func(10)) # quando chama a função externa, a função interna é executada
# resultado: 20
Funções como argumentos de outras funções
As funções também podem ser passadas como argumentos de outras funções. Veja um exemplo disso abaixo.
# Define uma função
def minha_func(numero):
return numero * 2
# Passa função como argumento de outra função
def chama_minha_func(func):
numero = 50
return func(numero)
print(chama_minha_func(minha_func))
# resultado: 100
Funções que retornam funções
Outra característica das funções do Python se refere à capacidade para gerar e retornar outras funções. Veja isso abaixo em um exemplo.
def func_oi(): # Define uma função
def diga_oi(): # Define uma função interna
return "Oi" # retorno da função interna
return diga_oi # retorno da função externa
oi = func_oi()
print(oi())
# resultado: Oi
Nesse tipo de padrão de design, uma função aninhada dentro de outra tem acesso às variáveis do escopo da função de delimitação (função externa). Este conceito, conhecido como fechamento, é crítico em decoradores (Python decorator). Ele é ilustrado no código abaixo.
def func_diga(mensagem):
def diga_mensagem():
print(mensagem) # acessa variável do escopo da função externa
diga_mensagem()
mensagem = 'Oi'
func_diga(mensagem)
# resultado: Oi
Python decorator na prática
Os conceitos vistos acima são a base para a criação de um Python decorator. Ilustraremos esse ponto com a criação de uma função que converte as palavras de uma frase em maiúsculas. Com decoradores, isso é feito definindo um invólucro (wrapper) em uma função fechada.
def decorador_maiusculas(function):
def wrapper():
func = function()
converte_maiusculas = func.upper()
return converte_maiusculas
return wrapper
def diga_oi():
return 'Eu falo oi'
decorador = decorador_maiusculas(diga_oi) # aplica o decorador na função diga_oi
print(decorador())
# resultado: EU FALO OI
Tipicamente, ao invés de chamar uma função dentro da outra, como mostrado acima, o Python possui uma sintaxe mais simples para o uso de decoradores. Ela consiste em usar o símbolo @ antes da função que queremos decorar seguido do nome do decorador que deve ser aplicado. Veja abaixo.
def decorador_maiusculas(function):
def wrapper():
func = function()
converte_maiusculas = func.upper()
return converte_maiusculas
return wrapper
@decorador_maiusculas
def diga_oi():
return 'Eu falo oi novamente'
print(diga_oi())
# resultado: EU FALO OI NOVAMENTE
Funções com múltiplos decoradores
Uma única função pode aceitar múltiplos decoradores Python. Isso é feito empilhando os decoradores acima da definição da função que se deseja modificar, usando a sintaxe @.
# primeiro decorador
def decorador_soma(function):
def wrapper():
func = function()
soma_dez = func + 10
return soma_dez
return wrapper
# segundo decorador
def decorador_divide(function):
def wrapper():
func = function()
divide_meio = func / 2
return divide_meio
return wrapper
# decoradores empilhados em uma função
@decorador_soma
@decorador_divide
def minha_func():
res = 100 * 3
return res
print(minha_func())
# resultado: 160.0
Decoradores Python com argumentos
Obviamente, decoradores Python aceitam argumentos. Isso é feito definindo um decorador que aceita argumentos e que possui outro decorador dentro dele para modificar a função. Veja um exemplo ilustrativo desse padrão abaixo.
def decorador_com_argumento(argumento): # decorador que aceita argumento
def decorador_de_func(function): # decorador de função
def wrapper(argumento): # função que modifica função
func = function(argumento)
soma_cinquenta = func + 50
return soma_cinquenta
return wrapper
return decorador_de_func
numero = 100
@decorador_com_argumento(numero)
def minha_func(numero): # função onde o decorador eh aplicado
res = numero * 2
return res
print(minha_func(numero))
# resultado: 250.0
Veja também:
Encontrou algum erro ou quer fazer uma sugestão? Por favor, entre em contato usando nosso formulário de contatos.