器指函数 装饰即修饰,意指为其他函数添加新功能 装饰器定义:本质就是函数,功能是为其他函数添加新功能
1.不能修改被修饰函数的源代码 2.不能修改被修饰函数的调用方式
现在有下面一个函数,如果我们要为这个函数添加一个功能:测试程序的运行时间。
import time list=[1,2,3,4,5] def cal(list): for i in list: time.sleep(0.5) print(i) cal(list)
import time list=[1,2,3,4,5] def cal(list): start_time=time.time() for i in list: time.sleep(0.5) print(i) stop_time=time.time() print("运行时间:%s" %(stop_time-start_time)) cal(list)
1
2
3
4
5
运行时间:2.502134323120117
总结:我们虽然实现了功能,但是我们要知道两大原则,现在我们直接修改函数的源代码,这样做是不行的。
装饰器=高阶函数+函数嵌套+闭包
高阶函数定义:
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
3.满足上述条件任意一个,都可称之为高阶函数
def foo(): print(‘我的函数名作为参数传给高阶函数‘) def gao_jie1(func): print(‘我就是高阶函数1,我接收的参数名是%s‘ %func) func() def gao_jie2(func): print(‘我就是高阶函数2,我的返回值是%s‘ %func) return func gao_jie1(foo) gao_jie2(foo)
只满足一个条件:函数接收的参数是一个函数名
import time def foo(): print(‘from the foo‘) def timmer(func): start_time=time.time() func() stop_time=time.time() print(‘函数%s 运行时间是%s‘ %(func,stop_time-start_time)) timmer(foo) #总结:我们确实为函数foo增加了foo运行时间的功能,但是foo原来的执行方式是foo(),现在我们需要调用高阶函数timmer(foo),改变了函数的调用方式
满足两个条件
1.函数接收的参数是一个函数名
2.函数的返回值是一个函数名
import time def foo(): print(‘from the foo‘) def timmer(func): start_time=time.time() return func stop_time=time.time() print(‘函数%s 运行时间是%s‘ %(func,stop_time-start_time)) foo=timmer(foo) foo() #总结:我们确实没有改变foo的调用方式,但是我们也没有为foo增加任何新功能
高阶函数总结
1.函数接收的参数是一个函数名
作用:在不修改函数源代码的前提下,为函数添加新功能,
不足:会改变函数的调用方式
2.函数的返回值是一个函数名
作用:不修改函数的调用方式
不足:不能添加新功能
def father(name): print(‘from father %s‘ %name) def son(): print(‘from son‘) def grandson(): print(‘from grandson‘) grandson() son() father(‘aaa‘)
闭包:闭包是指内部函数调用外部函数的变量
包是指嵌套,闭是指封装
def test1(): a=1 def test2(): print(a) test2() test1()
无参装饰器=高级函数+函数嵌套
1 #这就是一个实现一个装饰器最基本的架子 2 def timer(func): 3 def wrapper(): 4 func() 5 return wrapper
解决被修饰的函数是有参数的。
1 def timer(func): 2 def wrapper(*args,**kwargs): 3 func(*args,**kwargs) 4 return wrapper
import time def timmer(func):#func=test def wrapper(name,age): start_time = time.time() res=func(name,age) # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return res return wrapper # @timmer 等效于 test=timmer(test) @timmer def test(name,age): time.sleep(3) print(‘test函数运行完毕‘) return "这是test的返回值" res=test("lingling",20) print(res) @timmer # @timmer 等效于 test1=timmer(test1) def test1(name,age,gender): time.sleep(3) print(‘test函数运行完毕‘) return "这是test1的返回值" res=test1("lingling",20) print(res) #@timmer 等效于 test=timmer(test),#在这里一定要注意,我们首先把test函数传入到timmer装饰器,我们下一步返回了wrapper函数的地址(return wrapper)。 #test变量接收到wrapper函数的地址 #test("lingling",20)传入参数,执行wrapper函数,这里test函数有参数,为name,age,所以wrapper函数也应该有两个变量name,age,而执行wrapper函数,实际是要执行test函数,此处也需要两个参数,name,age #res变量接收到test函数执行的结果 # 1.将test函数传入timmer:timmer(test) # 2.执行timmer函数,返回wrapper函数地址(return wrapper) # 3.执行wrapper函数(执行wrapper函数实则是执行test函数),并接收test函数返回值:res=test("lingling",20)
import time def timmer(func):#func=test def wrapper(*wargs,**kwargs): start_time = time.time() res=func(*wargs,**kwargs) # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return res return wrapper @timmer def test(name,age): time.sleep(3) print(‘test函数运行完毕‘) return "这是test的返回值" res=test("lingling",age=20) print(res) @timmer def test1(name,age,gender): time.sleep(3) print(‘test1函数运行完毕‘) return "这是test1的返回值" res=test1("lingling",20,‘male‘) print(res) #解决wrapper不固定接收参数的问题 #如果细心可能会想,这里我们把wrapper参数写死了,你只能传入两个参数,如果有不同的函数需要这个装饰器,那我们不得重新修改装饰器,这真是一个大问题,我们来解决这个问题 #所以我们在wrapper函数中应该接收到test函数的所有参数:*wargs,**kwargs # *wargs:接收所有位置参数 # **kwargs:接收键值对类型的参数 #我们将wrapper函数与内部func函数的参数设置*wargs,**kwargs就可以接收所有传进来的参数 #第二个问题,func接收参数 # 使用*wargs,**kwargs怎么接收参数 # 就使用*wargs,**kwargs怎么传递参数 # 我们可以把*wargs,**kwargs看成一个整体,接收所有的参数
def test2(name,age,gender): #test2(*(‘alex‘,18,‘male‘),**{}) print(name) print(age) print(gender) def test1(*args,**kwargs): test2(*args,**kwargs) #args=(‘alex‘,18,‘male‘) kwargs={} test1(‘alex‘,18,‘male‘) def test3(*args,**kwargs): print(args) print(kwargs) # test3(1,2,3,4,name="linlin") test3(*(1,2,3,4),**{‘name‘:‘linlin‘})
在装饰器的框架基础上添加被测试函数所需要的功能。
import time def timer(func): def wrapper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) stop_time=time.time() print(‘函数[%s],运行时间是[%s]‘ %(func,stop_time-start_time)) return wrapper
import time def timmer(func):#func=test def wrapper(): start_time = time.time() func() # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return wrapper # @timmer 等效于 test=timmer(test) @timmer def test(): time.sleep(3) print(‘test函数运行完毕‘) test()
import time def timmer(func):#func=test def wrapper(): start_time = time.time() func() # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return wrapper def test(): time.sleep(3) print(‘test函数运行完毕‘) test=timmer(test)#返回的是wrapper的地址 test()#执行的是wrapper()
解决在测试程序里有返回值的情况。
import time def timer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print(‘函数[%s],运行时间是[%s]‘ %(func,stop_time-start_time)) return res return wrapper
import time def timmer(func):#func=test def wrapper(): start_time = time.time() res=func() # 就是在运行test() stop_time = time.time() print("函数运行时间的是%s" % (stop_time - start_time)) return res return wrapper # @timmer 等效于 test=timmer(test) @timmer def test(): time.sleep(3) print(‘test函数运行完毕‘) return "这是test的返回值" res=test() print(res)
如果我们需要使用装饰器,只需要在被测试的函数前加上@装饰器函数名
@timmer 等效于 test=timmer(test)
@timer #@timer就等同于cal=timer(cal) def cal(array): res=0 for i in array: res+=i return res cal(range(10))
博文:https://www.cnblogs.com/linhaifeng/articles/6140395.html
原文:https://www.cnblogs.com/-wenli/p/10651819.html