python3装饰器详细解析
python3装饰器(fuctional decorators)就是用于拓展原来函数功能的一种函数,目的在于不爱变原来函数名的情况下该函数添加新功能的方法。
一般而言,我们想要拓展原来的函数代码,最直接的方法就是进入代码里修改,例如:
import time
5 def f():
6 for i in range(10):
7 if i<=5:
8 print(i)
9 time.sleep(1)
10 i+=1
11 else:
12 print(i)
13
14
15 if __name__=='__main__':
16 f()
这是最原始的函数,现在想要记录下这个函数运行的总时间,最简单的方法就是改动原来的代码:
import time
20 def f():
21 start=time.time()
22 for i in range(10):
23 if i <=5:
24 print(i)
25 time.sleep(1)
26 i+=1
27 else:
28 print(i)
29 end=time.time()
30 execute_time=end-start
31 print('time is %d ms'%execute_time)
32
33 if __name__=='__main__':
34
35 f()
但是实际上有些核心代码在开发过程中不能直接更改,所以在不更改原来代码的情况下,我们可以在定义一个函数,在执行过程中需要再次 执行该函数
import time
41
42 def deco(f):
43
44 def cost_time():
45 start=time.time()
46 f()
47 end=time.time()
48 execute_time=end-start
49 print('time is %d ms'% execute_time)
50 return cost_time
51
52 @deco
53 def f():
54 for i in range(10):
55 if i<=5:
56 print(i)
57 time.sleep(1)
58 i+=1
59 else:
60 print(i)
61
62 if __name__=="__main__":
63 f()
这里我们定义一个函数deco,参数为一个函数,返回值也是一个函数,其中作为参数的这个函数f()就在返回函数cost_time()的内部执行,然后在函数f()前面加上一个@deco,f()就相当于被加入了计时功能,现在只需要调用f(),他就已经变为‘新的更多功能’的函数了。(不需要重复执行原函数)
扩展1:带有固定参数的装饰器
import time
69 def deco(f):
70 def add_sum(a,b):
71 start=time.time()
72 f(a,b)
73 end=time.time()
74 cost_time=(end-start)*1000
75 print('time is %d ms'% cost_time)
76 return add_sum
77
78 @deco
79 def f(a,b):
80 print('start')
81 time.sleep(1)
82 print('result is %d'% (a+b))
83
84
85 if __name__=='__main__':
86 f(3,4)
扩展2:无固定参数的装饰器
import time
94 def deco(f):
95 def cost_time(*args,**kwargs):
96 start=time.time()
97 f(*args,**kwargs)
98 end=time.time()
99 cost_time=(end-start)*1000
100 print('cost time %d ms'% cost_time)
101 return cost_time
102
103 @deco
104
105 def f(a,b,c):
106 print('start')
107 time.sleep(1)
108 print('sum=%d'%(a+b+c))
109
110 if __name__=='__main__':
111 f(3,4,5)
扩展3:基于类的装饰器
前面我们一直讨论装饰器修饰的都是一个函数,其实也可以定义基于类的装饰器。
class Bold(object):
def __init__(self,f):
self.f=f
def __call__(self, *args, **kwargs):
return "<b>"+ self.f(*args,**kwargs)+'</b>'
@Bold
def f():
return 'hello world'
if __name__=='__main__':
print(f())
__init__():用于初始化一个实例对象,它接受一个函数作为参数,也就是被装饰的函数
__call__():让一个实例对象可调用,就像函数调用一样,在调用被装饰函数时别调用
扩展4: 带参数的类装饰器
class Tag(object):
def __init__(self,tag):
self.tag=tag
def __call__(self, f):
def prapped(*args,**wargs):
return '<{tag}>{res}</{tag}>'.format(tag=self.tag,res=f(*args,**wargs))
return prapped
@Tag('b')
def f():
return 'hello world'
if __name__=='__main__':
print(f())
装饰器的调用顺序
装饰器是可以叠加使用的,在python中装饰器的调用顺序是与定义顺序相反的
python内置装饰器
在python中有三个内置装饰器,都是跟class相关的:staticmethod、classmethod和property
- staticmethod 是类静态方法,跟成员方法的区别是没有self参数,并且可以在不进行实例化的情况下调用
- classmethod 与成员方法的区别在于所接受的第一个参数不是self(类指针实例),而是cls(当前的具体类型)
- property 是属性的意思,表示可以通过类实例直接访问的信息