Decoradores Python

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_pricefunçã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_pricefunção calcula o preço líquido a partir do preço de venda e dos impostos. Ele retorna net_pricecomo um número.

Suponha que você precise formatar o preço líquido usando a moeda USD. Por exemplo, 100torna-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):
    passLinguagem de código:  Python  ( python )

E retorna outra função:

def currency(fn):
    def wrapper(*args, **kwargs):
        fn(*args, **kwargs)

    return wrapperLinguagem de código:  Python  ( python )

A currencyfunção retorna a wrapperfunção. A wrapperfunção possui os parâmetros *argse **kwargs.

Esses parâmetros permitem chamar qualquer fnfunção com qualquer combinação de argumentos posicionais e somente de palavras-chave .

Neste exemplo, a wrapperfunção essencialmente executa a fnfunção diretamente e não altera nenhum comportamento da fnfunção.

Na wrapperfunção, você pode chamar a fnfunçã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 wrapperLinguagem de código:  Python  ( python )

A currencyfunçã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 currencydecorador, você precisa passar a net_pricefunçã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 fnargumento 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_pricefunção usando a seguinte sintaxe:

net_price = currency(net_price)Linguagem de código:  Python  ( python )

Geralmente, se decoratefor 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():
    passLinguagem 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_pricefunção usando o @currencyseguinte:

@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 decoratefunção retorna uma nova função, que é a função wrapper.

Se você usar a função interna helppara 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 wrapsfunção do functoolsmódulo padrão. Na verdade, a wrapsfunção também é decoradora.

A seguir mostramos como usar o wrapsdecorador:

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 wrapsfunção do functoolsmódulo integrado para manter a documentação e o nome da função original.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *