python装饰器

it2022-05-05  95

开闭原则:在不修改原函数及其调用方式的情况下对原函数功能进行扩展对代码的修改是封闭不能修改被装饰的函数的源代码不能修改被装饰的函数的调用方式

用函数的方式设想一下游戏里用枪的场景

1 def game(): 2 print('压子弹') 3 print('枪上膛') 4 print('发射子弹') 5 game() 6 game() 7 game() 8 9 此时需要给枪增加一个瞄准镜,比如狙击远程目标时候需要加,狙击近程目标不用加 10 此时上边的代码就变成了现在的代码 11 12 def sight(): 13 print('专业狙击瞄准镜') 14 game() 15 sight() 16 sight() 17 sight() 18 此时的设计就不符合开闭原则(因为修改了原代码及调用名称)

装饰器(python里面的动态代理)本质: 是一个闭包组成: 函数+实参高阶函数+返回值高阶函数+嵌套函数+语法糖 = 装饰器存在的意义: 在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能

通用装饰器写法:

1 def warpper(fn): # fn是目标函数相当于func 2 def inner(*args,**kwargs): # 为目标函数的传参 3 '''在执行目标函数之前操作''' 4 ret = fn(*args,**kwargs) # 调用目标函数,ret是目标函数的返回值 5 '''在执行目标函数之后操作''' 6 return ret # 把目标函数返回值返回,保证函数正常的结束 7 return inner 8 9 #语法糖 10 @warpper #相当于func = warpper(func) 11 def func(): 12 pass 13 func() #此时就是执行的inner函数

上边的场景用装饰器修改后

1 方式一 2 def game(): 3 print('压子弹') 4 print('枪上膛') 5 print('发射子弹') 6 7 def sight(fn): # fn接收的是一个函数 8 def inner(): 9 print('安装专业狙击瞄准镜') 10 fn() #调用传递进来的函数 11 print('跑路') 12 return inner #返回函数地址 13 14 game = sight(game) #传递game函数到sight函数中 15 game() 16 17 执行步骤 18 第一步定义两个函数game()为普通函数,sight()为装饰器函数 19 第二步定义game = sight(game)等于把game函数当做参数传递给sight(fn)装饰器函数fn形参 20 第三步执行sight(fn),fn在形参位置,相当于下边函数game()传参过来等于fn 21 第四步执行inner函数,然后return把inner函数内存地址当做返回值返回给sight(game) 22 第五步然后执行game(),相当于执行inner函数 23 第六步,执行inner函数,打印'狙击镜',执行fn()形参,由于fn形参等于game函数,所以执行game()函数,打印'压子弹','上膛','发射子弹' 24 第七步打印'跑路' 25 第八步把打印的结果返回给game() 26 27 方式二 28 def sight(fn): # fn接收的是一个函数 29 def inner(): 30 print('安装专业狙击瞄准镜') 31 fn() #调用传递进来的函数 32 print('跑路') 33 return inner #返回函数地址 34 35 @sight #相当于game = sight(game) 36 def game(): 37 print('压子弹') 38 print('枪上膛') 39 print('发射子弹') 40 game() 41 42 执行步骤 43 第一步执行sight(fn)函数 44 第二步执行@sight,相当于把把game函数与sight装饰器做关联 45 第三步把game函数当做参数传递给sight(fn)装饰器函数fn形参 46 第四步执行inner函数,然后return把inner函数内存地址当做返回值返回给@sight 47 第五步执行game()相当相当于执行inner()函数,因为@sight相当于game = sight(game) 48 第六步打印'瞄准镜 49 第七步执行fn函数,因为fn等于game函数,所以会执行game()函数,打印'压子弹','上膛','发射子弹'.fn()函数执行完毕 50 第八步打印'跑路' 51 第九步然后把所有打印的结果返回给game() 52 53 结果 54 安装专业狙击瞄准镜 55 压子弹 56 枪上膛 57 发射子弹 58 跑路

一个简单的装饰器实现

1 def warpper(fn): 2 def inner(): 3 print('每次执行被装饰函数之前都要先经过这里') 4 fn() 5 return inner 6 @warpper 7 def func(): 8 print('执行了func函数') 9 func() 10 11 结果 12 每次执行被装饰函数之前都要先经过这里 13 执行了func函数

 带有一个或多个参数的装饰器

1 def sight(fn): #fn等于调用game函数 2 def inner(*args,**kwargs): #接受到的是元组("bob",123) 3 print('开始游戏') 4 fn(*args,**kwargs) #接受到的所有参数,打散传递给user,pwd 5 print('跑路') 6 return inner 7 @sight 8 def game(user,pwd): 9 print('登陆游戏用户名密码:',user,pwd) 10 print('压子弹') 11 print('枪上膛') 12 print('发射子弹') 13 game('bob','123') 14 结果 15 开始游戏 16 登陆游戏用户名密码: bob 123 17 压子弹 18 枪上膛 19 发射子弹 20 跑路

动态传递一个或多个参数给装饰器

1 def sight(fn): #调用game函数 2 def inner(*args,**kwargs): #接受到的是元组("bob",123) 3 print('开始游戏') 4 fn(*args,**kwargs) #接受到的所有参数,打散传递给正常的参数 5 print('跑路') 6 return inner 7 @sight 8 def game(user,pwd): 9 print('登陆游戏用户名密码:',user,pwd) 10 print('压子弹') 11 print('枪上膛') 12 print('发射子弹') 13 return '游戏展示完毕' 14 ret = game('bob','123') #传递了两个参数给装饰器sight 15 print(ret) 16 17 @sight 18 def car(qq): 19 print('登陆QQ号%s'%qq) 20 print('开始战车游戏') 21 ret2 = car(110110) #传递了一个参数给装饰器sight 22 print(ret2) 23 结果 24 开始游戏 25 登陆游戏用户名密码: bob 123 26 压子弹 27 枪上膛 28 发射子弹 29 跑路 30 None 31 开始游戏 32 登陆QQ号110110 33 开始战车游戏 34 跑路 35 None 36 你会发现这两个函数执行的返回值都为None,但是我game定义返回值了return '游戏展示完毕',却没给返回

装饰器的返回值

1 为什么我定义了返回值,但是返回值还是None呢,是因为我即使在game函数中定义了return '游戏展示完毕' 2 但是装饰器里只有一个return inner定义返回值,但是这个返回值是返回的inner函数的内存地址的,并不是inner 3 函数内部的return所以默认为None,所以应该定义一个inner函数内部的return返回值,而且也没有接收返回值的变量, 4 所以要要设置ret = fn(*args,**kwargs)和return ret 5 6 def sight(fn): #调用game函数 7 def inner(*args,**kwargs): #接受到的是元组("bob",123) 8 print('开始游戏') 9 ret = fn(*args,**kwargs) #接受到的所有参数,打散传递给正常的参数 10 print('跑路') 11 return ret 12 return inner 13 @sight 14 def game(user,pwd): 15 print('登陆游戏用户名密码:',user,pwd) 16 print('压子弹') 17 print('枪上膛') 18 print('发射子弹') 19 return '游戏展示完毕' 20 ret = game('bob','123') #传递了两个参数给装饰器sight 21 print(ret) 22 结果 23 开始游戏 24 登陆游戏用户名密码: bob 123 25 压子弹 26 枪上膛 27 发射子弹 28 跑路 29 游戏展示完毕 30 31 32 事例2 33 def wrapper_out(flag): #装饰器本身的参数 34 def wrapper(fn): #目标函数 35 def inner(*args,**kwargs): #目标函数需要接受的参数 36 if flag == True: 37 print('找第三方问问价格行情') 38 ret = fn(*args,**kwargs) 39 print('买到装备') 40 return ret 41 else: 42 ret = fn(*args,**kwargs) 43 return ret 44 return inner 45 return wrapper 46 #语法糖,@装饰器 47 @wrapper_out(True) 48 def func(a,b): #被wrapper装饰 49 print(a,b) 50 print('开黑') 51 return 'func返回值' 52 abc = func('我是参数1','我是参数2') 53 print(abc) 54 结果 55 找第三方问问价格行情 56 我是参数1 我是参数2 57 开黑 58 买到装备 59 func返回值

多个装饰器同用一个函数

1 def wrapper1(fn): 2 def inner(*args,**kwargs): 3 print('wrapper1-1') 4 ret = fn(*args,**kwargs) 5 print('wrapper1-2') 6 return ret 7 return inner 8 9 def wrapper2(fn): 10 def inner(*args,**kwargs): 11 print('wrapper2-1') 12 ret = fn(*args,**kwargs) 13 print('wrapper2-2') 14 return ret 15 return inner 16 17 def wrapper3(fn): 18 def inner(*args,**kwargs): 19 print('wrapper3-1') 20 ret = fn(*args,**kwargs) 21 print('wrapper3-2') 22 return ret 23 return inner 24 @wrapper1 25 @wrapper2 26 @wrapper3 27 def func(): 28 print('我是测试小白') 29 func() 30 结果 31 wrapper1-1 32 wrapper2-1 33 wrapper3-1 34 我是测试小白 35 wrapper3-2 36 wrapper2-2 37 wrapper1-2

转载于:https://www.cnblogs.com/selina1997/p/10146401.html

相关资源:各显卡算力对照表!

最新回复(0)