函数__装饰器
一.装饰器.
装饰器: 在目标函数前和后插入一段新的代码,不改变原来的代码.装饰器是对原来基础功能的扩展和开放,又不变动原代码,所以比较安全.
装饰器的本质是一个闭包。什么是闭包,就是内层函数对外层函数的变量的引用。
装饰器语法
# 通用装饰器写法: # python里面的动态代理. # 存在的意义: 在不破坏原有函数和原有函数调用的基础上. 给函数添加新的功能 def wrapper(fn): # fn是目标函数. def inner(*args, **kwargs): # 为了目标函数的传参 '''在执行目标函数之前.....''' ret = fn(*args, **kwargs) # 调用目标函数, ret是目标函数的返回值 '''在执行目标函数之后....''' return ret # 把目标函数返回值返回. 保证函数正常的结束 return inner @wrapper # target_func = wrapper(target_func) #此处的wrapper 一定记住:是不加括号的,不是调用!!! def target_func(): pass # target_func = wrapper(target_func) # 此时fn就是target_func target_func() # 此时执行的是inner
def outer(a): b = 1 def inner(): print(a + b) return inner
# 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数
if __name__ == '__main__':
inner = outer(1) inner()
下面是简易版装饰器
def play(username, password): print("双击lol") print("登录", username, password) print("选择狂战士") print("进草丛") return "月之光芒" def xiaoxiaole(qq): print("登录qq账号") print("消消乐") def wrapper(fn): # fn = play def inner(*args, **kwargs): # 无敌传参 接受到的是元组 ("alex", 123) print("开挂") ret = fn(*args, **kwargs) # 接受到的所有参数. 打散传递给正常的参数 return ret 接收函数的返回值 return inner play = wrapper(play) # play = inner ret = play('alex',"123") print(ret) 输出结果: 开挂 双击lol 登录 alex 123 选择狂战士 进草丛 月之光芒
带参数的装饰器(装饰器的开关).
def wrapper_out(flag): # 装饰器本身的参数 def wrapper(fn): # 目标函数 def inner(*args, **kwargs): # 目标函数执行需要的参数 if flag == True: #如果开关为False,就不进行函数的装饰 print("问问金老板. 行情怎么样啊") #执行函数之前 ret = fn(*args, **kwargs) # 在执行函数本身 print("金老板骗我. 恨你") #执行函数之后 return ret else: ret = fn(*args, **kwargs) #执行函数本身 return ret return inner return wrapper # 语法糖 @装饰器 @wrapper_out(True) # 先执行wrapper_out(True) 返回一个装饰器 再和@拼接 @装饰器 def yue(): # 被 wrapper装饰 print("走啊. 约不?") yue()
解释1: 不理解为何会变?: 写完一个函数之后,不指定对象的调用它,你print这个函数,打印出来的内容,除了函数里的,一定还有它自己的返回值,说白了,此时的调用完之后,函数已经变成了它自己的返回值 解释2: 此时,这里变成了@wrapper,是个语法糖,就是python设计的语法上的简写,他和后面定义的函数,合在一起等值于 b=wrapper(b)(此时的函数名b就等于inner函数名,再调用就是调用的inner()函数)
解释3:
如果这里的参数True改为False,那么就无法执行该函数,会报错,这里的Alex(True)是让函数正常执行,执行完了,会变成该函数的返回值 → wrapper,而@wrapper下面定义的函数意味着,就是wrapper函数括号里参数,
而你再用这个参数名接收返回值,该函数名就变成了返回值,你之后再调用的实际是装饰器内部的函数,如果你想关闭装饰器,就把True,改为Flase,就可以了
装饰器的应用:
# 装饰器在登陆验证方面的应用. flag =False #没登陆的状态为False def login(): #此函数为登陆函数,只有登陆成功,才会显示成功登陆的状态(flag = True) global flag zhanghao =input("请输入账号:") mima = input("请输入密码:") if zhanghao=="alex" and mima=="123": flag = True return "登陆成功" else: print("对不起,输入有误.") exit() def zhuangshi1(a): def zhuangshi(fn): #装饰器函数 def inner(*can1,**can2): while 1: if flag == True: print("装饰器把你装饰了一番,你NB了") ret = fn(*can1,**can2) return ret,"从此人生达到巅峰!" #此处有多个返回值,会变成元组形式返回 else: print("对不起,您还没登陆.") login() return inner return zhuangshi @zhuangshi1(True) def wangzhe(a,b): print("玩家",a,"进入了游戏") return "得到月之光芒剑" a = wangzhe("alex","123456") print(a) 打印结果为: 对不起,您还没登陆. 请输入账号:alex 请输入密码:123 装饰器把你装饰了一番,你NB了 玩家 alex 进入了游戏 ('得到月之光芒剑', '从此人生达到巅峰!')
多个装饰器装饰同一个函数:
def wrapper1(fn): def inner(*args, **kwargs): print("装饰1111111") ret = fn(*args, **kwargs) print("装饰1111111") return ret return inner def wrapper2(fn): def inner(*args, **kwargs): print("装饰2222222") ret = fn(*args, **kwargs) print("装饰2222222") return ret return inner #就近原则 @wrapper1 #后被它装饰 @wrapper2 #先被此装饰器装饰 def func(): print("我是幸运的func") func() 输出结果为: 装饰1111111 装饰2222222 我是幸运的func 装饰2222222 装饰1111111