English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
El decorador acepta una función, agrega algunas funciones y devuelve la función. En este artículo, aprenderás cómo crear decoradores y por qué se utiliza.
Python tiene una función interesante llamadaDecoradores, que puede agregar funcionalidades al código existente.
También se llamaMeta-programación,Porque parte del programa intenta modificar otra parte del programa en tiempo de compilación.
Para entender los decoradores, primero debemos entender algunos conocimientos básicos de Python.
Debemos aceptar el hecho de que todo en Python esObjetos. Los nombres que definimos solo son identificadores de estos objetos.FuncionesNo son la excepción, también son objetos (con propiedades). Se pueden asignar diferentes nombres al mismo objeto funcional.
Este es un ejemplo.
def first(msg): print(msg) first("Hello") second = first second("Hello")
Cuando ejecuta el código, estas dos funciones first y second dan el mismo resultado. Aquí, los nombres first y second hacen referencia al mismo objeto funcional.
Ahora, ¿no parece que se ha vuelto un poco más complicado, pasar funciones como parámetros a otras funciones?.
Si ha utilizado funciones como map, filter y reduce en Python, ya sabe esto.
Este tipo de funciones que toman otras funciones como parámetros también se llamaFunciones de orden superior. Esto es un ejemplo de este tipo de función.
def inc(x): devolver x + 1 def dec(x): devolver x - 1 def operate(func, x): resultado = func(x) devolver resultado
Llamamos a la función de la siguiente manera.
>>> operate(inc,3) 4 >>> operate(dec,3) 2
Además, una función puede devolver otra función.
def is_called(): def is_returned(): print("Hello") devolver is_returned new = is_called() #Salida "Hello" new()
Aquí, is_returned() es una función anidada que se define y devuelve cada vez que llamamos a is_drawn().
Finalmente, debemos entenderClosures en Python.
Las funciones y métodos se denominanInvocables,Porque pueden ser llamados.
En realidad, cualquier objeto que implemente el método especial __call__() se considera invocable. Por lo tanto, en el sentido más básico, los decoradores son invocables y pueden devolver invocables.
Básicamente, los decoradores aceptan una función, agregan algunas funcionalidades y la devuelven.
def make_pretty(func): def inner(): print(\"Me decoré\") func() return inner def ordinary(): print(\"Soy una función común\")
Al ejecutar el siguiente código en el shell,
>>> ordinary() Soy una función común >>> # Decoramos esta función común >>> pretty = make_pretty(ordinary) >>> pretty() Me decoré Soy una función común
En el ejemplo mostrado, make_pretty() es un decorador. En el paso de asignación.
pretty = make_pretty(ordinary)
La función ordinary() se decoró, y la función devuelta se llama pretty.
Podemos ver que el decorador agrega algunas nuevas funcionalidades al función original. Esto es similar a embalar un regalo. El decorador actúa como embalaje. La naturaleza del artículo decorado (el regalo dentro) no cambia. Pero ahora, parece muy bonito (desde que se decoró).
Por lo general, decoramos una función y la reasignamos como
ordinary = make_pretty(ordinary).
Esta es una construcción común, por lo que Python tiene una sintaxis simplificada para esto.
Podemos usar el símbolo @ junto con el nombre del decorador de función y colocarlo en la definición de la función que se va a decorar. Por ejemplo,
@make_pretty def ordinary(): print(\"Soy una función común\")
is equivalent to
def ordinary(): print(\"Soy una función común\") ordinary = make_pretty(ordinary)
Esto es solo un azúcar sintáctico para implementar decoradores.
El decorador anterior es simple y solo se aplica a funciones sin parámetros. ¿Qué haremos si nuestra función tiene los siguientes parámetros?
def divide(a, b): return a/b
Esta función tiene dos parámetros,aandbSabiendo que si vamos abSe produce un error si se pasa 0.
>>> divide(2,5) 0.4 >>> divide(2,0) Traceback (llamada más reciente última): ... ZeroDivisionError: división por cero
Ahora vamos a hacer un decorador para verificar si esto causará un error.
def smart_divide(func): def inner(a,b): print(\"Voy a hacer una división", a, \"y\", b) if b == 0: print(\"¡Oh! No se puede dividir\") return return func(a,b) return inner @smart_divide def divide(a,b): return a/b
If an error occurs, this new implementation will return None.
>>> divide(2,5) I want to do division 2 and 5 0.4 >>> divide(2,0) I want to do division 2 and 0 Oops! Cannot divide
In this way, we can decorate functions with parameters.
A keen observer will notice that the parameters of the nested function inside the inner() decorator are the same as those of the function it decorates. Considering this, now we can make the universal decorator usable with any number of parameters.
In Python, this magic is achieved by the completed function(*args, **kwargs). In this way, args are positional argumentstupleInstead of positional arguments, usedictionary. An example of such a decorator is.
def works_for_all(func): def inner(*args, **kwargs): I can decorate any function return func(*args, **kwargs) return inner
Multiple decorators can be chained in Python.
This means that a function can be decorated multiple times (or the same) with different decorators. We just need to place the decorators above the required function.
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")
This will give the output.
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
the above syntax,
@star @percent def printer(msg): print(msg)
is equivalent to
def printer(msg): print(msg) printer = star(percent(printer))
The order of the decorators is important. If we reverse the order,
@percent @star def printer(msg): print(msg)
The execution will occur
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%