Resumo : neste tutorial, você aprenderá sobre decoradores Python e como desenvolver seus próprios decoradores.
O que é um decorador em Python
Um decorador é uma função que toma outra função como argumento e estende seu comportamento sem alterar explicitamente a função original.
Vamos dar um exemplo simples para entender o conceito.
Um exemplo simples de decorador Python
O seguinte define uma net_price
função:
def net_price(price, tax):
""" calculate the net price from price and tax
Arguments:
price: the selling price
tax: value added tax or sale tax
Return
the net price
"""
return price * (1 + tax)
Linguagem de código: Python ( python )
A net_price
função calcula o preço líquido a partir do preço de venda e dos impostos. Ele retorna net_price
como um número.
Suponha que você precise formatar o preço líquido usando a moeda USD. Por exemplo, 100
torna-se $100
. Para fazer isso, você pode usar um decorador.
Por definição, um decorador é uma função que recebe uma função como argumento:
def currency(fn):
pass
Linguagem de código: Python ( python )
E retorna outra função:
def currency(fn):
def wrapper(*args, **kwargs):
fn(*args, **kwargs)
return wrapper
Linguagem de código: Python ( python )
A currency
função retorna a wrapper
função. A wrapper
função possui os parâmetros *args
e **kwargs
.
Esses parâmetros permitem chamar qualquer fn
função com qualquer combinação de argumentos posicionais e somente de palavras-chave .
Neste exemplo, a wrapper
função essencialmente executa a fn
função diretamente e não altera nenhum comportamento da fn
função.
Na wrapper
função, você pode chamar a fn
função, obter seu resultado e formatar o resultado como uma string de moeda:
def currency(fn):
def wrapper(*args, **kwargs):
result = fn(*args, **kwargs)
return f'${result}'
return wrapper
Linguagem de código: Python ( python )
A currency
função é um decorador.
Ele aceita qualquer função que retorne um número e formate esse número como uma string monetária.
Para usar o currency
decorador, você precisa passar a net_price
função para ele para obter uma nova função e executar a nova função como se fosse a função original. Por exemplo:
net_price = currency(net_price)
print(net_price(100, 0.05))
Linguagem de código: Python ( python )
Saída:
$105.0
Definição de decorador Python
Em geral, um decorador é:
- Uma função que recebe outra função (função original) como argumento e retorna outra função (ou encerramento )
- O encerramento normalmente aceita qualquer combinação de argumentos posicionais e somente de palavras-chave.
- A função de fechamento chama a função original usando os argumentos passados para o fechamento e retorna o resultado da função.
A função interna é um fechamento porque faz referência ao fn
argumento de seu escopo envolvente ou da função decoradora.
O símbolo
No exemplo anterior, a moeda é um decorador. E você pode decorar a net_price
função usando a seguinte sintaxe:
net_price = currency(net_price)
Linguagem de código: Python ( python )
Geralmente, se decorate
for uma função decoradora e você quiser decorar outra função fn
, você pode usar esta sintaxe:
fn = decorate(fn)
Linguagem de código: Python ( python )
Para torná-lo mais conveniente, Python oferece um caminho mais curto como este:
@decorate
def fn():
pass
Linguagem de código: Python ( python )
Por exemplo, em vez de usar a seguinte sintaxe:
net_price = currency(net_price)
Linguagem de código: Python ( python )
… você pode decorar a net_price
função usando o @currency
seguinte:
@currency
def net_price(price, tax):
""" calculate the net price from price and tax
Arguments:
price: the selling price
tax: value added tax or sale tax
Return
the net price
"""
return price * (1 + tax)
Linguagem de código: Python ( python )
Junte tudo.
def currency(fn):
def wrapper(*args, **kwargs):
result = fn(*args, **kwargs)
return f'${result}'
return wrapper
@currency
def net_price(price, tax):
""" calculate the net price from price and tax
Arguments:
price: the selling price
tax: value added tax or sale tax
Return
the net price
"""
return price * (1 + tax)
print(net_price(100, 0.05))
Linguagem de código: Python ( python )
Introspecção de funções decoradas
Quando você decora uma função:
@decorate
def fn(*args,**kwargs):
pass
Linguagem de código: Python ( python )
É equivalente:
fn = decorate(fn)
Linguagem de código: Python ( python )
A decorate
função retorna uma nova função, que é a função wrapper.
Se você usar a função interna help
para mostrar a documentação da nova função, não verá a documentação da função original. Por exemplo:
help(net_price)
Linguagem de código: Python ( python )
Saída:
wrapper(*args, **kwargs)
None
Além disso, se você verificar o nome da nova função, o Python retornará o nome da função interna retornada pelo decorador:
print(net_price.__name__)
Linguagem de código: Python ( python )
Saída:
wrapper
Portanto, ao decorar uma função, você perderá a assinatura e a documentação originais da função.
Para corrigir isso, você pode usar a wraps
função do functools
módulo padrão. Na verdade, a wraps
função também é decoradora.
A seguir mostramos como usar o wraps
decorador:
from functools import wraps
def currency(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
result = fn(*args, **kwargs)
return f'${result}'
return wrapper
@currency
def net_price(price, tax):
""" calculate the net price from price and tax
Arguments:
price: the selling price
tax: value added tax or sale tax
Return
the net price
"""
return price * (1 + tax)
help(net_price)
print(net_price.__name__)
Linguagem de código: Python ( python )
Saída:
net_price(price, tax)
calculate the net price from price and tax
Arguments:
price: the selling price
tax: value added tax or sale tax
Return
the net price
net_price
Linguagem de código: JavaScript ( javascript )
Resumo
- Um decorador é uma função que altera o comportamento de outra função sem modificá-la explicitamente.
- Use o
@
símbolo para decorar uma função. - Use a
wraps
função dofunctools
módulo integrado para manter a documentação e o nome da função original.