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

[Python basics 007] take you to analyze Python decorator functions in depth

編輯:Python

 

Catalog

Preface :

One 、 Decorator —— Formation process

Two 、 Decorator —— First knowledge of grammar sugar

3、 ... and 、 Decorator —— Essence and function

Four 、 Decorator —— Decorative belt parameters , Decorators that return values

1、 Decorate a function with one argument

2、 Decorate multiple functions with different parameters but no return value

3、 Decorate multiple functions with different parameters and return values

4、 Multiple decorators decorate the same function

5、 ... and 、 Decorator ——  Advanced and optimized decorator

1、 Parameter decorator

2、 Prevent the necessary information of the function from invalidating

6、 ... and 、 Decorator —— Decoration principles

1、 Open and closed principle

Summary :

1、 Fixed format of decorator ( Templates )



Preface :

Suppose I write a function f

def f():
print('hello')

Then I want to know how long this function will take to execute , It's easy to do , I just need to change the code to the following

import time
def f():
start = time.time() # Get the start time of program execution
print('hello')
end = time.time() # Get the end time of program execution
print(end - start) # Get the function f Execution time
f()

But then I wrote countless functions f2,f3……fn, I want to know how long each function takes to execute , So if you change everything like the above , Isn't it annoying ? Not yet. , Because it's too much trouble . Then what shall I do? ? So I had an idea , Wrote a timer function ...

import time
def timer(func):
start = time.time()
func()
print(time.time() - start)
def f():
print('hello')
def f2():
print('xorld')
timer(f)
timer(f2)

Isn't it a lot easier ? No matter how many functions we write, we can call this timing function to calculate the execution time of the function

But if I just want to do it the same way f1(),f2(),fn() Called this function , The function can also increase the function of calculation time on the premise that the original execution output result remains unchanged , Instead of calling timer(f),timer(f2) To calculate time , What should I do ?

After looking at the decorator function below, you will know how to solve this problem



One 、 Decorator —— Formation process

Here is a simple version of the code that solves the above problem :

import time
def f():
print('hello')
def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner
f = timer(f)
f()

I just want to use the original way f1(),f2(),fn() Called this function , The function can also increase the function of calculation time on the premise that the original execution output result remains unchanged , But I'm still going to be in the function f Write before execution f = timer(f) In this string of code , Do you think it's an eyesore ?python The developers of the company also feel it's an eyesore , therefore python Our developers have provided us with a sentence Grammatical sugar To solve this problem !



Two 、 Decorator —— First knowledge of grammar sugar

use @timmer Instead of f = timer(f), This is a grammatical sugar .

import time
def timer(func):
def inner():
start = time.time()
func()
print(time.time() - start)
return inner
@timer #==> Writing this sentence is equivalent to executing f = timer(f)
def f():
print('hello')
f()



3、 ... and 、 Decorator —— Essence and function

1、 The essence

         The essence of decorator is a closure function

2、 function

         Extend the function of the original function without modifying the original function and its calling method



Four 、 Decorator —— Decorative belt parameters , Decorators that return values

  • 1、 Decorate a function with one argument

The decorators we just wrote are decorating functions without parameters , Now how to decorate a function with parameters ?

import time
def timer(func):
def inner(a):
start = time.time()
func(a)
print(time.time() - start)
return inner
@timer
def f(a):
print(a)
f('hello')
  • 2、 Decorate multiple functions with different parameters but no return value

In fact, decorating functions with parameters is not difficult , But if you have two functions , The parameters to be passed are different , such as   function func1 There are two parameters func1(a ,b), function func 2 There is only one parameter func2(a),  And they all want to decorate with this decorator , Calculate the function execution time ? So what do we do ? Then use the following code .

import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner
@timer #==> func1 = timer(func1)
def func1(a,b):
print('in func1')
@timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over'
func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))
Output results :
in func1
0.0
in func2 and get a:aaaaaa
0.0
fun2 over
  • 3、 Decorate multiple functions with different parameters and return values

Now the parameter problem has been solved perfectly , But what if your function has a return value ? With the above code, you can't get the return value. How do you solve this problem ? Let's look at the following code !

import time
def timer(func):
def inner(*args,**kwargs):
start = time.time()
re = func(*args,**kwargs)
print(time.time() - start)
return re
return inner
@timer #==> func2 = timer(func2)
def func2(a):
print('in func2 and get a:%s'%(a))
return 'fun2 over'
func2('aaaaaa')
print(func2('aaaaaa'))
Output results :
in func2 and get a:aaaaaa
0.0
in func2 and get a:aaaaaa
0.0
fun2 over
  • 4、 Multiple decorators decorate the same function

Sometimes , We will also use multiple decorators to decorate the same function .

ef wrapper1(func): #func ----- f
def inner1():
print('wrapper1 ,before func')
func()
print('wrapper1 ,after func')
return inner1
def wrapper2(func):
def inner2():
print('wrapper2 ,before func')
func()
print('wrapper2 ,after func')
return inner2
@wrapper2 #f = wrapper2(f) ----->> wrapper2(inner1) == inner2
@wrapper1 #f = wrapper1(f) = inner
def f():
print('in f')
f() #===>>inner2
# Multiple decorators decorate the same function
Output results :
wrapper2 ,before func
wrapper1 ,before func
in f
wrapper1 ,after func
wrapper2 ,after func



5、 ... and 、 Decorator ——  Advanced and optimized decorator

  • 1、 Parameter decorator

The decorator above is already very beautiful 了 , But there is a problem , If I add... To countless functions in my code @timer This syntax sugar , If I don't want to use it anymore, wouldn't it be necessary for everyone to annotate it , Working day and night 3 God ? Isn't it particularly troublesome , In order to better recycle decorators when they are not in use, instead of commenting or deleting them one by one We introduce the concept of decorators with parameters

'''
In order to better recycle decorators when they are not in use, instead of commenting or deleting them one by one
We introduce the concept of decorators with parameters
'''
import time
'''FLAGE Its purpose is to use it to control the switch of the decorator ,
So when we don't use it, we don't need to comment one by one, just put True Change it to False Just go '''
FLAGE = True
def timmer_out(flag):
def timmer(func):
def inner(*args,**kwargs):
if flag:
start = time.time()
ret = func(*args,**kwargs)
end = time.time()
print(end - start)
return ret
else:
ret = func(*args, **kwargs)
return ret
return inner
return timmer
@timmer_out(FLAGE)
#timmer_out(FLAGE)
# It is also equivalent to executing timmer_out(FLAGE)--->> return timmer———————>>@timmer(wahaha = timmer(wahaha))
def wahaha():
time.sleep(0.1) # If you don't rest, the function executes too fast to calculate the time
print('wahahahahahaha')
wahaha()
@timmer_out(FLAGE)
def erguotou():
time.sleep(0.1) # If you don't rest, the function executes too fast to calculate the time
print('erguotoutoutou')
erguotou()
Output results :
wahahahahahaha
0.10152268409729004
erguotoutoutou
0.10795140266418457
  • 2、 Prevent the necessary information of the function from invalidating

'''
print(wahaha.__name__) # View the function name in string format
print(wahaha.__doc__) # View the comments for a function
'''
# The following is used __name__ see holiday The function name of
from functools import wraps
def wrapper(func):
@wraps(func) # Right above the innermost function
def inner(*args,**kwargs):
print(' What to do before the decorated function is executed ')
ret = func(*args,**kwargs)
print(' What to do after the decorated function is executed ')
return ret
return inner
@wrapper #holiday = wrapper(holiday)
def holiday(day):
'''
This is a holiday notice
:param day:
:return:
'''
print(' All holidays %s God '%day)
return ' So happy '
print(holiday.__name__)
print(holiday.__doc__)
'''
The result is inner and None But what we want is to print holiday The string format of the function name and function comments ?
The solution is from functools import wraps
Using grammar is @wraps( Decorated function name )
'''
Output results :
holiday
This is a holiday notice
:param day:
:return:



6、 ... and 、 Decorator —— Decoration principles

  • 1、 Open and closed principle

1. The function extension of the original function is open

         Why should we be open to functional extensions ?

For any program , It's impossible to have all the functions in mind at the beginning of the design without any update or modification in the future . So we have to allow later extensions 、 Add new features .

2. Closed to changes

         Why is it necessary to close the amendment ?

                 As we just mentioned , Because we wrote a function , It is likely that it has been imported and used elsewhere , If we change it at this time , It is likely to affect other code that is already using this function .

The decorator perfectly follows this open and closed principle . This is the original intention of learning decorators



Summary :

  • 1、 Fixed format of decorator ( Templates )

# Format 1
def timer(func):
def inner(*args,**kwargs):
''' What to do before executing the function '''
re = func(*args,**kwargs)
''' What to do after executing the function '''
return re
return inner
# Format two
from functools import wraps
def deco(func):
@wraps(func) # Right above the innermost function
def wrapper(*args,**kwargs):
return func(*args,**kwargs)
return wrapper

Finally, thank you for seeing here :

In an unpublished article, Lu Xun said :“ If you understand the code, you must operate it yourself, so that you can better understand and absorb .”
One last sentence : A man can succeed in anything he has unlimited enthusiasm , Let's make progress together


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