【第十八天】装饰器
7.3
1.装饰器
装饰器(decorator)是一种高级py语法,装饰器可以对一个函数,方法或者类进行加工
在py中,我们有多种方法对函数和类进行加工,装饰器从操作上入手
为函数增加额外的指令,py最初没有装饰器这一语法
装饰器在py2.5中才出现,最初只用于函数
在py2.6以及之后的py版本中,装饰器被进一步用于类
我们先定义两个简单的数学函数,一个用来计算平方和
一个用来计算平方差:
#获得平方和
def square_sum(a,b):
return a**2 + b**2
#获得平方差
def square_diff(a,b):
return a**2 - b**2
if __name__ == '__main__':
print(square_sum(3,4)) #打印25
print(square_diff(3,4)) #打印-7
在拥有了基本的数学功能之后,我们可能想为函数增加其他的功能
比如打印输入,我们可以改写函数来实现这一点:
#装饰:打印输入
def square_sum(a,b):
print('input:',a,b)
return a**2 + b**2
def square_diff(a,b):
print('input:',a,b)
return a**2 - b**2
if __name__ == '__main__':
print(square_sum(3,4))
print(square_diff(3,4))
我们修改了函数定义,为函数增加了功能,从代码中可以看到
这两个函数在功能上的拓展有很高的相似性
都是增加了print('input:',a,b)这一打印功能
我们可以改用装饰器,定义功能拓展本身
再把装饰器用于两个函数:
def decorator_demo(old_function):
def new_function(a,b):
print('input',a,b) #额外打印操作
return old_function(a,b)
return new_function
@decorator_demo
def square_sum(a,b):
return a**2 + b**2
@decorator_demo
def square_diff(a,b):
return a**2 - b**2
if __name__ == '__main__':
print(square_sum(3,4))
print(square_diff(3,4))
装饰器可以用def的形式定义,如上面代码中的decorator_demo()
装饰器接受一个可调用的对象作为输入参数,并返回一个新的可调用对象
装饰器新建了一个函数对象,也就是上面的new_function()
在new_function()中,我们增加了打印的功能
并通过调用old_function(a,b)来保留原有函数的功能
定义好装饰器后,我们就可以通过@语法使用了
在函数square_sum()和square_diff()定义之前
调用@decorator_demo,实际上是将square_sum()
或square_diff()传递给了decorator_demo()
并将decorator_demo()返回的新的函数对象赋给原来的函数名
square_sum()和square_diff()
所以当我们调用square_sum(3,4)的时候,实际上发生的是:
square_sum = decorator_demo(square_sum)
square_sum(3,4)
我们知道,py中的变量名和对象是分离的
变量名其实是指向一个对象的引用
从本质上,装饰器起到的作用就是名称绑定(name binding)
让同一个变量名指向一个新返回的函数对象,从而达到修改函数对象的目的
只不过,我们很少彻底更改函数对象,在使用装饰器时
我们往往会在新函数内部调用旧的函数,以便保留旧函数功能
下面看一个更有实用功能的装饰器,我们可以利用time包来测量程序运行的时间
把测量程序运行时间的功能做成一个装饰器,将这个装饰器运用于其他函数
将显示函数的实际运行时间:
import time
def decorator_timer(old_function):
def new_function(*arg,**dict_arg):
t1 = time.time()
result = old_function(*arg,**dict_arg)
t2 = time.time()
print('time:',t2 - t1)
return result
return new_function
@decorator_timer
def sum(a,b):
c = a + b
return c
if __name__ == '__main__':
print(sum(3,4))
time: 1.1920928955078125e-06
7
在new_function()中,除调用旧函数外
还前后额外调用了一次time.time(),由于time.time()返回挂钟时间
它们的差值反映了旧函数的运行时间,此外,我们通过打包参数的方法
可以在新函数和旧函数之间传递所有的参数
装饰器可以实现代码的可复用性,我们可以用同一个装饰器修饰多个函数
以便实现相同的附加功能,比如说,在建设网站服务器时,我们能用不同函数
表示对不同HTTP请求的处理,当我们每次处理HTTP请求前
都想附加一个客户验证功能时,那么就可以定义一个统一的装饰器
作用于每一个处理函数,这样,程序能重复利用,可读性也大为提高
Python中的函数的参数定义和可变参数
https://www.cnblogs.com/tqsummer/archive/2011/01/25/1944416.html