Explain Python decorator with examples
- 2021-08-31 08:44:14
- OfStack
In Python, a function can be passed into a function as a parameter, and a function can also be copied to a variable, and a function can be called through a variable. The decorator can extend the function of a function, make a decorator annotation for the function, and execute the functions defined in the decorator in advance in all functions, thus improving the reuse degree of the code.
Now there is such a scene.
Clock in
There are all kinds of employees in Internet companies, programmers, front desk... programmers need to punch in before turning on the computer, and the front desk needs to open the door early (I don't know who opens the door, assuming here that the front desk opens the door), and the front desk also needs to punch in before opening the door. That is to say, punching in is the first public action of all employees, so the function of punching in can be taken out as public logic.
Common function call method
Naturally, it can be realized as follows.
def di(f):
print('%s Clock in , Drop ...' % f.__name__)
return f()
def boot():
print(' Turn on ')
def open():
print(' Open the door ')
if __name__ == '__main__':
"""
Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk.
"""
di(boot)
di(open)
A function di (f) is defined, which can print the function name information of f.__name__, that is, f, and return the execution result of f ().
Note: If __name__ is imported as a module, module.__name__ is the name of the module itself, and if the module itself is executed as a script, it returns __main__.
Implementation results:
boot punch in, drop...
Turn on
open punch in, drop...
Open the door
In this design, if there are many functions to call, it is very troublesome, so the decorator will come in handy.
Simple Decorator with @ Grammar Sugar
Decorator: A way to add functionality dynamically while code is running, called a "decorator" (Decorator).
Simple decorator
Define an di (f) method, or pass in the logical function to be executed as a parameter, which defines an wrapper function, and the return value is the execution result of f.
In if __name__ = = '__main__':, this decorator is called, and the defined function is not modified, and the function "punch in" is dynamically added during operation.
import functools
# Simple decorator
def di(f):
"""
Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk.
:param f: Incoming 1 Functions
:return:
"""
# Put the original function's __name__ And other properties are copied to the wrapper()
@functools.wraps(f)
def wrapper():
print('%s Clock in , Drop ...' % f.__name__)
return f()
return wrapper
def boot():
print(' Turn on ')
def open():
print(' Open the door ')
if __name__ == '__main__':
# No. 1 1 Kinds, simple decorator
a = di(boot)
a1 = di(open)
print(a.__name__) # Results wrapper Plus @functools.wraps(f) The result is boot
a()
a1()
The return value a of di (boot) is the wrapper function, and the wrapper function is called through a () to get the return value of boot. Similarly, di (open) 1.
Results
boot
boot punch in, drop...
Turn on
open punch in, drop...
Open the door
Since the return value a of di (boot) is the wrapper function, the result of print (a.__name__) is of course wrapper. We hope it is boot. What should I do? The annotation of functools. wraps (f) can copy the attributes such as __name__ of the original function boot to wrapper (), and this line of code annotation can also run, so the result of print (a.__name__) is wrapper.
The second kind, @ grammar sugar
With @ grammar sugar, you can also apply decorators to functions. Recommended.
import functools
def di(f):
"""
Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk.
:param f: Incoming 1 Functions
:return:
"""
# Put the original function's __name__ And other properties are copied to the wrapper()
@functools.wraps(f)
def wrapper():
print('%s Clock in , Drop ...' % f.__name__)
return f()
return wrapper
# @ Grammatical sugar
@di
def boot2():
print(' Turn on ')
@di
def open2():
print(' Open the door ')
if __name__ == '__main__':
# No. 1 2 Species, @ Grammatical sugar
boot2()
open2()
The @ di tag is equivalent to a2 = di (boot2) a2 (). Don't bother, because the @ symbol is added, you can call the decorator directly with boot2 ().
Results
boot2 punch in, drop...
Turn on
open2 punch in, drop...
Open the door
Business logic function requires parameters
Business logic functions may require parameters, such as:
def boot(name):
print('%s Turn on ' % name)
Then, just modify the front decorator to:
import functools
# Business logic function requires parameters
def di(f):
"""
Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk.
:param f: Incoming 1 Functions
:return:
"""
# Put the original function's __name__ And other properties are copied to the wrapper()
@functools.wraps(f)
def wrapper(*args, **kwargs):
print('%s Clock in , Drop ...' % f.__name__)
return f(*args, **kwargs)
return wrapper
@di
def boot(name):
print('%s Turn on ' % name)
if __name__ == '__main__':
boot('keguang')
Results:
boot punch in, drop...
keguang boot
Add * args and **kwargs parameters to wrapper, and call f (* args, **kwargs) directly in boot. By the way, 1:
* args: 1 Array parameter can be passed in **kwargs: 1 k-v pair parameter can be passed inThe sequence corresponds, and the array parameters come first. Examples:
def f(*args, **kwargs):
print('args=', args)
print('kwargs=', kwargs)
print(f(1, 2, 3, a = 'a', b = 'b'))
# Results
# args= (1, 2, 3)
# kwargs= {'a': 'a', 'b': 'b'}
Decorator with parameters
If the decorator also takes parameters, for example, now if an employee comes to work early in the morning, < At 9:00, we can give a compliment, which is equivalent to putting a layer of function outside the front di (), di_args, inside wrapper. Use this parameter
import functools
# Decorator with parameters
def di_args(time):
def di(f):
"""
Programmers need to punch in the fingerprint machine outside the door before turning on the machine and opening the door at the front desk.
:param f: Incoming 1 Functions
:return:
"""
# Put the original function's __name__ And other properties are copied to the wrapper()
@functools.wraps(f)
def wrapper(*args, **kwargs):
if time < '9:00':
print(' It's so early. It's great. . . ')
print('%s Clock in , Drop ...' % f.__name__)
return f(*args, **kwargs)
return wrapper
return di
@di_args('8:00')
def boot(name):
print('%s Turn on ' % name)
if __name__ == '__main__':
boot('keguang')
Parameters can be passed in at @ di_args ('8:00'), which is a bit like the annotation in java. Finally, it can be called through boot ('keguang'), and the result is:
It's so early. It's great. . .
boot punch in, drop...
keguang boot
Class decorator
The class decorator relies primarily on the __call__ method of the class, which is called when the decorator is attached to a function using the @ form.
# Class decorator
class di(object):
def __init__(self, f):
self._f = f
def __call__(self, *args, **kwargs):
print('decorator start...')
self._f()
print('decorator end...')
@di
def boot():
print(' Turn on ')
if __name__ == '__main__':
boot()
With the @ di decorator identity, the di class is instantiated with boot, then the __call__ function is executed, and object indicates that the class can pass in any type parameter.
Running result
decorator start...
Turn on
decorator end...
A typical application scenario of decorator is to log log. If all logic needs to log the running status of the program, you can add log module decorator to these logic (functions) to achieve the corresponding purpose.
The above is an example to explain the details of Python decorator. For more information about python decorator, please pay attention to other related articles on this site!