How to use the decorator in python
- 2021-11-10 10:20:35
- OfStack
2. To respond to all changes with the same, it is also a change
3. Minimize changes
4. Use decorators for functions with arguments
Step 5 Give decorator parameters
6. Decorator with class parameters
7. Apply more than one decorator to a function
8. As a class
1. How does the demand come from
The definition of decorator is very abstract. Let's look at a small example.
def foo():
print('in foo()')
foo()
This is a boring function. That's right. But suddenly one of the more boring people, we call him B Jun, said I want to see how long it takes to execute this function, OK, then we can do this:
import time
def foo():
start = time.time()
print('in foo()')
time.sleep(2)
end = time.time()
print(f'used:{end - start}')
foo()
Good, the function looks impeccable. However, B, who is in pain, suddenly doesn't want to see this function at the moment, and he is more interested in another function called foo2.
What shall I do? If you copy the above newly added code to foo2, it will be a big taboo ~ isn't it the most annoying to copy something! Moreover, what if B continued to look at other functions?
2. To respond to all changes with the same, it is also a change
Remember, the function is a first-class citizen in Python, so we can consider redefining a function timeit, passing the reference of foo to him, and then calling foo in timeit and timing it, so that we can achieve the purpose of not changing the definition of foo, and no matter how many functions B looks at, we don't have to modify the definition of the function!
import time
def foo():
print('in foo()')
def timeit(func):
start = time.time()
func()
time.sleep(2)
end = time.time()
print('used:', end - start)
timeit(foo)
It seems that there is no logical problem, 1 cut is beautiful and works normally! ..... Wait, we seem to have modified the code of the calling part. Originally, we called it this way: foo (), but after modification, it became: timeit (foo). In this case, if foo is called at N, you will have to modify the code at N. Or more extreme, consider the situation where the code called somewhere can't be modified, for example, this function is given to others for use.
3. Minimize changes
In this case, let's think of a way not to modify the calling code; If the calling code is not modified, it means that calling foo () needs to have the effect of calling timeit (foo). We can think of assigning timeit to foo, but timeit seems to take one parameter... find a way to unify the parameters to one! If timeit (foo) does not directly produce the calling effect, but returns a function corresponding to foo parameter list 1... it is very easy to handle. Assign the return value of timeit (foo) to foo, and then the code for calling foo () does not need to be modified at all!
# -*- coding: UTF-8 -*-
import time
def foo():
print('in foo()')
# Definition 1 Timer, passed in 1 And return another 1 Methods with additional timing function
def timeit(func):
# Definition 1 Embedded wrapper function, which wraps the incoming function with timing function
def wrapper():
start = time.time()
func()
time.sleep(2)
end = time.time()
print('used:', end - start)
# Returns the wrapped function
return wrapper
foo = timeit(foo)
foo()
In this way, a simple timer is ready! We only need to add foo = timeit (foo) after defining foo and before calling foo to achieve the purpose of timing, which is the concept of decorator, which looks like foo is decorated by timeit. In this example, the function is timed in and out, which is called a cross-section (Aspect), and this programming method is called section-oriented programming (Aspect-Oriented Programming). Compared with the top-down execution mode used by traditional programming, it is like inserting a piece of logic horizontally in the flow of function execution. In a specific business area, a large amount of duplicate code can be reduced. There are quite a few terms for aspect-oriented programming, so we won't introduce them here. If you are interested, you can look for relevant information.
This example is for demonstration only and does not take into account the foo with parameters and return values. It is up to you to perfect it:)
It seems that the above code can no longer be simplified, so Python provides a syntax sugar to reduce the input of characters.
import time
def timeit(func):
def wrapper():
start = time.time()
func()
time.sleep(2)
end = time.time()
print('used:', end - start)
return wrapper
@timeit
def foo():
print('in foo()')
foo()
Focus on @ timeit in line 11. Adding this line to the definition is exactly equivalent to writing foo = timeit (foo). Never think @ has other magic. In addition to 1 less character input, there is one additional benefit: it looks more decorator-like.
As you can see here, the decorator in python is essentially a function, which takes other functions as parameters and replaces them with a brand-new modified function.
4. Use decorators for functions with arguments
If the function to be wrapped has parameters, it is not troublesome. As long as the parameters and return values of the embedded wrapper function are the same as those of the original function, the decorative function can return the embedded wrapper function object
import datetime,time
def out(func):
def inner(*args):
start = datetime.datetime.now()
func(*args)
end = datetime.datetime.now()
print(end-start)
print("out and inner")
return inner
@out
def myfunc(*args):
time.sleep(1)
print("args is{}".format(args))
myfunc("lalalal")
Step 5 Give decorator parameters
It is not difficult to pass parameters to the decorator. Compared with the previous example, there is only one layer of packaging on the outer layer
#coding:utf-8
def outermost(*args):
def out(func):
print (" Decorator parameters {}".format(args))
def inner(*args):
print("innet start")
func(*args)
print ("inner end")
return inner
return out
@outermost(666)
def myfun(*args):
print (" Try the case where both decorators and functions take parameters , Decorated function parameters {}".format(args))
myfun("zhangkun")
6. Decorator with class parameters
It doesn't matter what type the parameter is. You see, the parameter is a class.
class locker:
def __init__(self):
print("locker.__init__() should be not called")
@staticmethod
def acquire():
print("locker.acquire() static method be called")
@staticmethod
def release():
print("locker.release() static method be called")
def outermost(cls):
def out(func):
def inner():
cls.acquire()
func()
cls.release()
return inner
return out
@outermost(locker)
def myfunc():
print("myfunc called")
myfunc()
7. Apply more than one decorator to a function
1 function can have multiple decorators, but pay attention to the order
class mylocker:
def __init__(self):
print("mylocker.__init__() called.")
@staticmethod
def acquire():
print("mylocker.acquire() called.")
@staticmethod
def unlock():
print(" mylocker.unlock() called.")
class lockerex(mylocker):
@staticmethod
def acquire():
print("lockerex.acquire() called.")
@staticmethod
def unlock():
print(" lockerex.unlock() called.")
def lockhelper(cls):
def _deco(func):
def __deco2(*args, **kwargs):
print("before %s called." % func.__name__)
cls.acquire()
try:
return func(*args, **kwargs)
finally:
cls.unlock()
return __deco2
return _deco
class example:
@lockhelper(mylocker)
@lockhelper(lockerex)
def myfunc2(self, a, b):
print(" myfunc2() called.")
print(a+b)
a = example()
a.myfunc2(1,2)
8. As a class
Although decorators can almost always be implemented as functions, in some cases, it may be better to use user-defined classes
import time
class DerocatorAsClass:
def __init__(self,funcation):
self.funcation = funcation
def __call__(self, *args, **kwargs):
# Before calling the function , Do something
result = self.funcation(*args,**kwargs)
print('3333333333')
# Do something after the call and return the result
return result
@DerocatorAsClass
def foo():
print('in foo()')
foo()
As in the above example, it is also very convenient to use classes as decorators
The above is the python decorator how to use the details, more information about the use of python decorator please pay attention to other related articles on this site!