python装饰器

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

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

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

通用装饰器写法:app

复制代码
 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函数
复制代码

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

复制代码
 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 跑路
复制代码

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

复制代码
 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
相关文章
相关标签/搜索