Decoradores Python
Decoradores Python
Um decorador recebe uma função, adiciona alguma funcionalidade e a retorna. Neste tutorial, você aprenderá como criar um decorador e por que deve usá-lo.
Vídeo:@Decorators em Python
Decoradores em Python
Python tem um recurso interessante chamado decoradores para adicionar funcionalidade a um código existente.
Isso também é chamado de metaprogramação porque uma parte do programa tenta modificar outra parte do programa em tempo de compilação.
Pré-requisitos para aprender decoradores
Para entender sobre decoradores, devemos primeiro conhecer algumas coisas básicas em Python.
Devemos estar confortáveis com o fato de que tudo em Python (Sim! Mesmo classes), são objetos. Os nomes que definimos são simplesmente identificadores vinculados a esses objetos. As funções não são exceções, elas também são objetos (com atributos). Vários nomes diferentes podem ser vinculados ao mesmo objeto de função.
Aqui está um exemplo.
def first(msg):
print(msg)
first("Hello")
second = first
second("Hello")
Saída
Hello Hello
Quando você executa o código, ambas as funções
first
e second
dar a mesma saída. Aqui, os nomes first
e second
referem-se ao mesmo objeto de função. Agora as coisas começam a ficar mais estranhas.
Funções podem ser passadas como argumentos para outra função.
Se você usou funções como
map
, filter
e reduce
em Python, então você já sabe disso. Essas funções que recebem outras funções como argumentos também são chamadas de funções de ordem superior . Aqui está um exemplo de tal função.
def inc(x):
return x + 1
def dec(x):
return x - 1
def operate(func, x):
result = func(x)
return result
Chamamos a função da seguinte forma.
>>> operate(inc,3)
4
>>> operate(dec,3)
2
Além disso, uma função pode retornar outra função.
def is_called():
def is_returned():
print("Hello")
return is_returned
new = is_called()
# Outputs "Hello"
new()
Saída
Hello
Aqui,
is_returned()
é uma função aninhada que é definida e retornada toda vez que chamamos is_called()
. Finalmente, devemos saber sobre Closures em Python.
Voltando aos Decoradores
Funções e métodos são chamados de chamáveis como podem ser chamados.
Na verdade, qualquer objeto que implemente o
__call__()
especial método é denominado callable. Então, no sentido mais básico, um decorador é um callable que retorna um callable. Basicamente, um decorador recebe uma função, adiciona alguma funcionalidade e a retorna.
def make_pretty(func):
def inner():
print("I got decorated")
func()
return inner
def ordinary():
print("I am ordinary")
Quando você executa os seguintes códigos no shell,
>>> ordinary()
I am ordinary
>>> # let's decorate this ordinary function
>>> pretty = make_pretty(ordinary)
>>> pretty()
I got decorated
I am ordinary
No exemplo mostrado acima,
make_pretty()
é um decorador. Na etapa de atribuição:
pretty = make_pretty(ordinary)
A função
ordinary()
foi decorado e a função retornada recebeu o nome pretty
. Podemos ver que a função decoradora adicionou algumas novas funcionalidades à função original. Isso é semelhante a embalar um presente. O decorador atua como um wrapper. A natureza do objeto que foi decorado (presente real dentro) não se altera. Mas agora, está bonito (já que foi decorado).
Geralmente, decoramos uma função e a reatribuímos como,
ordinary = make_pretty(ordinary).
Essa é uma construção comum e, por esse motivo, o Python possui uma sintaxe para simplificar isso.
Podemos usar o
@
símbolo junto com o nome da função do decorador e coloque-o acima da definição da função a ser decorada. Por exemplo,
@make_pretty
def ordinary():
print("I am ordinary")
é equivalente a
def ordinary():
print("I am ordinary")
ordinary = make_pretty(ordinary)
Este é apenas um açúcar sintático para implementar decoradores.
Decorando funções com parâmetros
O decorador acima era simples e só funcionava com funções que não tinham nenhum parâmetro. E se tivéssemos funções que recebessem parâmetros como:
def divide(a, b):
return a/b
Esta função tem dois parâmetros, a e b . Sabemos que dará um erro se passarmos b como 0.
>>> divide(2,5)
0.4
>>> divide(2,0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
Agora vamos fazer um decorador para verificar este caso que causará o erro.
def smart_divide(func):
def inner(a, b):
print("I am going to divide", a, "and", b)
if b == 0:
print("Whoops! cannot divide")
return
return func(a, b)
return inner
@smart_divide
def divide(a, b):
print(a/b)
Esta nova implementação retornará
None
se a condição de erro ocorrer.
>>> divide(2,5)
I am going to divide 2 and 5
0.4
>>> divide(2,0)
I am going to divide 2 and 0
Whoops! cannot divide
Desta forma, podemos decorar funções que recebem parâmetros.
Um observador atento notará que os parâmetros do
inner()
aninhado função dentro do decorador é o mesmo que os parâmetros das funções que ele decora. Levando isso em consideração, agora podemos fazer decoradores gerais que funcionam com qualquer número de parâmetros. Em Python, essa mágica é feita como
function(*args, **kwargs)
. Dessa forma, args
será a tupla de argumentos posicionais e kwargs
será o dicionário de argumentos de palavras-chave. Um exemplo de tal decorador será:
def works_for_all(func):
def inner(*args, **kwargs):
print("I can decorate any function")
return func(*args, **kwargs)
return inner
Encadeando Decoradores em Python
Vários decoradores podem ser encadeados em Python.
Ou seja, uma função pode ser decorada várias vezes com decoradores diferentes (ou iguais). Simplesmente colocamos os decoradores acima da função desejada.
def star(func):
def inner(*args, **kwargs):
print("*" * 30)
func(*args, **kwargs)
print("*" * 30)
return inner
def percent(func):
def inner(*args, **kwargs):
print("%" * 30)
func(*args, **kwargs)
print("%" * 30)
return inner
@star
@percent
def printer(msg):
print(msg)
printer("Hello")
Saída
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
A sintaxe acima de,
@star
@percent
def printer(msg):
print(msg)
é equivalente a
def printer(msg):
print(msg)
printer = star(percent(printer))
A ordem em que encadeamos os decoradores é importante. Se tivéssemos invertido a ordem como,
@percent
@star
def printer(msg):
print(msg)
A saída seria:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
python
- Tipos de dados Python
- Operadores Python
- Instrução de passagem do Python
- Argumentos da função Python
- Função anônima/Lambda do Python
- Funções do Python Lambda com EXEMPLOS
- Função Python abs():exemplos de valor absoluto
- Função Python round() com EXEMPLOS
- Função range() do Python:Float, List, For loop Exemplos
- Função Python map() com EXEMPLOS