Home > Article > Backend Development > A closer look at Python decorator functions
This article brings you relevant knowledge about python, which mainly organizes issues related to decorator functions, including the formation process, essence and function, advancement and optimization of decorators Let’s take a look at the content below. I hope it will be helpful to everyone.
Recommended learning: python
If I write a function f
def f(): print('hello')
, I want to know this paragraph The time required for function execution is easy to handle. I just need to change the code to the following
import time def f(): start = time.time() #获取程序执行开始的时间 print('hello') end = time.time() #获取程序执行结束的时间 print(end - start) #得出函数f执行所要时间 f()
But then I wrote countless functions f2, f3...fn, and I want to know how long each function takes to execute. time, wouldn’t it be very annoying if we change it as above? Still not possible, because it would be too much trouble. then what should we do? So I had an idea and 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)
Doesn’t this look much simpler? 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 call this function in the original way f1(), f2(), fn(), The function can also add the function of calculating time while the original execution output result remains unchanged. Instead of calling timer(f), timer(f2) can calculate time. What should we do?
You will know how to solve this problem after reading the decorator function below
The following is the solution A simple version of the code for the above question:
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()
Still with this sentence, I just want to call this function in the original way f1(), f2(), fn(). The function outputs the result when it is originally executed. Under the premise of changing, the function of calculating time can be added, but I still have to write f = timer(f) in this string of code before the function f is executed. Does it feel annoying? Python developers also find it annoying, so Python developers provide us with a syntax sugar to solve this problem!
Use @timmer instead of f = timer(f), this is a sentence of syntactic sugar.
import time def timer(func): def inner(): start = time.time() func() print(time.time() - start) return inner @timer #==> 写着这句话就相当于执行了f = timer(f) def f(): print('hello') f()
1. Essence
The essence of a decorator is a closure function
2. FunctionExpand the original function function without modifying the original function and its calling method
4. Decoration Decorator - decorator with parameters and return valueimport 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')
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')) 输出结果: in func1 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
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')) 输出结果: in func2 and get a:aaaaaa 0.0 in func2 and get a:aaaaaa 0.0 fun2 over
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 #多个装饰器装饰同一个函数 输出结果: wrapper2 ,before func wrapper1 ,before func in f wrapper1 ,after func wrapper2 ,after func
''' 为了使装饰器不用时能够更好的回收而不是一个一个去注释或者删除 我们引入带参数的装饰器概念 ''' import time '''FLAGE的目的是用它控制装饰器的开关, 那么当我们不用的时候就不要一个一个去注释只需将True改为False就行''' 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) # 也相当于执行 timmer_out(FLAGE)--->>返回timmer———————>>@timmer(wahaha = timmer(wahaha)) def wahaha(): time.sleep(0.1) #不休息的话函数执行的太快难以计算时间 print('wahahahahahaha') wahaha() @timmer_out(FLAGE) def erguotou(): time.sleep(0.1) #不休息的话函数执行的太快难以计算时间 print('erguotoutoutou') erguotou() 输出结果: wahahahahahaha 0.10152268409729004 erguotoutoutou 0.10795140266418457
''' print(wahaha.__name__) #查看字符串格式的函数名 print(wahaha.__doc__) #查看一个函数的注释 ''' #下面用__name__查看holiday的函数名 from functools import wraps def wrapper(func): @wraps(func) #加在最内层函数正上方 def inner(*args,**kwargs): print('在被装饰的函数执行之前做的事') ret = func(*args,**kwargs) print('在被装饰的函数执行之后做的事') return ret return inner @wrapper #holiday = wrapper(holiday) def holiday(day): ''' 这是一个放假通知 :param day: :return: ''' print('全体放假%s天'%day) return '好开心' print(holiday.__name__) print(holiday.__doc__) ''' 结果是inner和None 但我们想要的是打印holiday的字符串格式的函数名和函数的注释这时该怎么办? 解决方法就是 from functools import wraps 使用语法是@wraps(被装饰的函数名) ''' 输出结果: holiday 这是一个放假通知 :param day: :return:
1、开放封闭原则
1.对原函数的功能扩展是开放的
为什么要对功能扩展开放呢?
对于任何一个程序来说,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改。所以我们必须允许后来扩展、添加新功能。
2.对修改是封闭的
为什么要对修改封闭呢?
就像我们刚刚提到的,因为我们写的一个函数,很有可能在其他地方已经被导入使用了,如果这个时候我们对其进行了修改,很有可能影响其他已经正在使用该函数的代码。
装饰器就完美遵循了这个开放封闭原则。这就是学装饰器的初衷
1、装饰器的固定格式(模板)
#格式一 def timer(func): def inner(*args,**kwargs): '''执行函数之前要做的''' re = func(*args,**kwargs) '''执行函数之后要做的''' return re return inner #格式二 from functools import wraps def deco(func): @wraps(func) #加在最内层函数正上方 def wrapper(*args,**kwargs): return func(*args,**kwargs) return wrapper
推荐学习:python
The above is the detailed content of A closer look at Python decorator functions. For more information, please follow other related articles on the PHP Chinese website!