程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Understand Python decorator @, the most detailed and simple tutorial

編輯:Python

Preface

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 .

Text

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 .

 

summary

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)


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved