Introdução
Esta seção introduz o conceito de um decorator (decorador). Este é um tópico avançado, do qual apenas arranharemos a superfície.
This tutorial is from open-source community. Access the source code
Esta seção introduz o conceito de um decorator (decorador). Este é um tópico avançado, do qual apenas arranharemos a superfície.
Considere uma função.
def add(x, y):
return x + y
Agora, considere a função com algum logging (registro) adicionado.
def add(x, y):
print('Calling add')
return x + y
Agora, uma segunda função também com algum logging (registro).
def sub(x, y):
print('Calling sub')
return x - y
Observação: É um pouco repetitivo.
Escrever programas onde há muita replicação de código é frequentemente muito irritante. São tediosos de escrever e difíceis de manter. Especialmente se você decidir que quer mudar como funciona (isto é, talvez um tipo diferente de logging (registro)).
Talvez você possa criar uma função que cria funções com logging (registro) adicionado a elas. Um wrapper (envoltório).
def logged(func):
def wrapper(*args, **kwargs):
print('Calling', func.__name__)
return func(*args, **kwargs)
return wrapper
Agora use-o.
def add(x, y):
return x + y
logged_add = logged(add)
O que acontece quando você chama a função retornada por logged?
logged_add(3, 4) ## Você vê a mensagem de logging aparecer
Este exemplo ilustra o processo de criação de uma chamada função wrapper (envoltório).
Um wrapper (envoltório) é uma função que envolve outra função com alguns pedaços extras de processamento, mas, de outra forma, funciona exatamente da mesma maneira que a função original.
>>> logged_add(3, 4)
Calling add ## Saída extra. Adicionada pelo wrapper
7
>>>
Nota: A função logged() cria o wrapper (envoltório) e o retorna como resultado.
Colocar wrappers (envoltórios) em torno de funções é extremamente comum em Python. Tão comum que existe uma sintaxe especial para isso.
def add(x, y):
return x + y
add = logged(add)
## Sintaxe especial
@logged
def add(x, y):
return x + y
A sintaxe especial executa exatamente as mesmas etapas mostradas acima. Um decorador é apenas uma nova sintaxe. Diz-se que ele decora a função.
Existem muitos detalhes mais sutis sobre decoradores do que o que foi apresentado aqui. Por exemplo, usá-los em classes. Ou usar múltiplos decoradores com uma função. No entanto, o exemplo anterior é uma boa ilustração de como seu uso tende a surgir. Normalmente, é em resposta a código repetitivo que aparece em uma ampla gama de definições de funções. Um decorador pode mover esse código para uma definição central.
Se você define uma função, seu nome e módulo são armazenados nos atributos __name__ e __module__. Por exemplo:
>>> def add(x,y):
return x+y
>>> add.__name__
'add'
>>> add.__module__
'__main__'
>>>
Em um arquivo timethis.py, escreva uma função decoradora timethis(func) que envolve uma função com uma camada extra de lógica que imprime quanto tempo leva para uma função ser executada. Para fazer isso, você envolverá a função com chamadas de medição de tempo como esta:
start = time.time()
r = func(*args,**kwargs)
end = time.time()
print('%s.%s: %f' % (func.__module__, func.__name__, end-start))
Aqui está um exemplo de como seu decorador deve funcionar:
>>> from timethis import timethis
>>> @timethis
def countdown(n):
while n > 0:
n -= 1
>>> countdown(10000000)
__main__.countdown : 0.076562
>>>
Discussão: Este decorador @timethis pode ser colocado na frente de qualquer definição de função. Assim, você pode usá-lo como uma ferramenta de diagnóstico para ajuste de desempenho.
Parabéns! Você concluiu o laboratório de Decoradores de Funções. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.