learning python When decorating , The articles on the Internet are usually understandable in the front, and then suddenly they can't understand , It may also be a bad brain . So write it down so that you can forget to look it up later , Also help the latecomers better understand python Decorator .
python The function of ornaments
Simply put, it means adding new functions to this function without changing the original function . Application scenarios : Inserting log , Login authorization, etc . I haven't used it, and I don't know , But it will definitely be useful to work in an enterprise in the future . For example, the boss asks you to add new functions , You can't change the code in a function , After all, enterprise code is ancestral code , I don't know how many people have written , If you accidentally move something that should not be moved, it is likely to crash the program , So at this time, the function of the decorator is particularly important .
python The use of decorators
python Everything is object , Since they are all objects , The arguments passed by the function can be string objects , Integer object , Of course, it can also be a function object .
def wrapper(func):
def inner():
print(" Suppose you need to print me in the function execution ")
re = func()
print(" Suppose you need to print me after the function is completed ")
return re
return inner
def func():
print("in func")
return "func return"
func = wrapper(func)
print(func)
print(func())
"""
Running results
<function wrapper.<locals>.inner at 0x0000023344A3F510>
Suppose you need to print me in the function execution
in func
Suppose you need to print me after the function is completed
func return
"""
It is estimated that everyone can understand this code , take func Function is passed as an argument to wrapper function , stay func Perform some operations on the function before and after its execution . This is it. python The simplest way to use a decorator .
python Grammatical sugar @ Use
Grammar sugar doesn't add new features , It's just a different way of writing , Without it, the implementation of your program will not be affected .
Write before the decorated function @wrapper amount to func=wrapper(func), The above code is also equivalent to the following code
def wrapper(func):
def inner():
print(" Suppose you need to print me in the function execution ")
re = func()
print(" Suppose you need to print me after the function is completed ")
return re
return inner
@wrapper
def func():
print("in func")
return "func return"
print(func)
print(func())
But the use of @ One thing that makes grammar sugar different is whether you call it or not func Function he will execute decorating function ( That is to say wrapper function ), It is executed when the module is loaded @wrapper This operation ( It can be understood as func=wrapper(func)). So if you return more than one function object in the decorator function , But also did some operations ( Like printing 、 Program hibernation, etc ), And you don't call the decorated function yet , May cause the program to run bug( But most people don't do that , I found it by accident ).
The decorator transmits parameters
If you understand the above, you can easily understand the parameters , Look at an example
def wrapper(func):
def inner(a,b,*args,**kwargs):
print(" Suppose you need to print me in the function execution ")
re = func(a,b,*args,**kwargs)
print(" Suppose you need to print me after the function is completed ")
return re
return inner
@wrapper
def func(a,b,*args,**kwargs):
print("in func")
print(a,b)
print(args,kwargs)
return "func return"
print(func)
print(func(1,2,3,4,5,k=5,j=6))
"""
Running results
<function wrapper.<locals>.inner at 0x0000020A61FDF510>
Suppose you need to print me in the function execution
in func
1 2
(3, 4, 5) {'k': 5, 'j': 6}
Suppose you need to print me after the function is completed
func return
"""
It's easy to understand , function func It is equivalent to running wrapper Inside the function inner, The first two parameters are given to a,b Of , The following dynamic parameter transfer , Those without key values are given as tuples args, Those with key values are given in the form of a dictionary kwargs.
You may think you understand , Don't worry. Let's take a look at the following example
Multi nested decorators
import time
def timmer(*args,**kwargs):
print(args,kwargs)
def wrapper(f):
print(args,kwargs)
def inner(*args,**kwargs):
print(args,kwargs)
if flag:
start_time = time.time()
ret = f(*args,**kwargs)
time.sleep(0.3)
end_time = time.time()
print(' The execution efficiency of this function %f' % (end_time-start_time))
else:
ret = f(*args, **kwargs)
return ret
return inner
return wrapper
flag = True
@timmer(flag,2,3)
def func1(*args,**kwargs):
return 666
#func1 = timmer(flag,2,3)(func1)
print(func1(1,2))
"""
Running results
(True, 2, 3) {}
(True, 2, 3) {}
(1, 2) {}
The execution efficiency of this function 0.300833
666
"""
If you don't pay attention to follow the previous idea ,func1 = wrapper,func1(1,2) = wrapper(1,2), But the result of this program is completely different from what we thought , It is easy to know from the running results that the program has called inner() Function , however wrapper Function just returns inner, To be called inner The function should be func1(1,2)() That's right . Then find out what the problem is in different places from the previous code , Careful little friends should be able to find , Before using grammar sugar @ Only the object address is followed , This is like a function call . you 're right , That's the topic .
The right way of thinking
In fact, we just @timmer(flag,2,3) Understood as a : First call timmer(flag,2,3) Function returns an object wrapper, And then execute @wrapper. According to what I learned before , have access to func1 = timmer(flag,2,3)(func1) replace @timmer(flag,2,3), The results are the same . It should be noted that flag Is a global variable , Although we didn't pass the parameters , But you can still use .
( There's one thing I haven't figured out , stay wrapper Inside printing args and kwargs It can be printed out and sent to timmer Value , Please let me know if you have any friends , Or I'll update it after I figure it out )
Then there are several decorators decorating a function 、wraps Module used , These difficulties are easy to understand , I won't repeat many of them on the Internet , You can see here , Part of the code in this article comes from this article , This is also the best one I have seen so far .
In short, it's in func1 Before to add @wrapper It is equivalent to running when the program starts to load modules func1=wrapper(func1), and @wrapper(1,2) Is equal to a=wrapper(1,2) func1=a(func1)