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

Learn more about Python decorator functions

編輯:Python

This article brings you about python Knowledge about , It mainly sorts out the related problems of decorator functions , Including the forming process of the decorator 、 Essence and function 、 Advanced and optimization , Let's take a look at , Hopefully that helped .

  • Recommend learning :python

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 The developers of the java.com provide us with a syntax 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
  • Recommend learning :python
  • Reprinted from :www.php.cn/python-tuto…

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