一.今日内容总览python
关于函数的装饰器
1.装饰器(重点,难点)(要求:反复写,代码很少可是很绕)
开闭原则:(好比,菜单是拆散的,一点点搞的,用友拆散本身的功能,之后就不用开发了)
(1)对功能的扩展开放
(2)对代码的修改是封闭的
通用装饰器语法:
def wrapper(fn):
def inner(*args,**kwargs): #聚合
#在目标函数以前的操做
ret=fn(*args,**kwargs) #打散
在目标函数以后
return inner
@wrapper #等价于 func=wrapper(func)
def func():
pass
func()
NC(用友,脑残)
2.同一个函数 被多个装饰器装饰
@wrapper1
@wrapper2
@wrapper3
def func():
pass
1 2 3 func 3 2 1
总结:就近原则,一层一层写
3.带参数的装饰器(难受)(明白函数的调用就行)
def wrapper_out(参数):
def wrapper(fn):
def inner(*args,**kwargs): #聚合
#在目标函数以前
ret=fn(*args,**kwargs) #打散
#在目标函数以后
return ret
return inner
return wrapper
@wrapper_out(实参) #执行的时候,先执行函数调用,而后使用返回值和前面的@组合成装饰器语法糖
def func():
pass
二.今日内容大纲app
1.开闭原则函数
2.装饰器测试
3.带参数的装饰器优化
4.多个装饰器装饰同一个函数spa
5.装饰器的应用设计
三.今日内容详解代理
1.开闭原则日志
开闭原则:
对功能的扩展开放;
对代码的修改是封闭的.
def chi(): print('吃东西') print('喝东西') chi() chi() #显然不是咱们想要的,对程序继续优化
2.装饰器code
(1)
女娲 造人 补天
热插拔:有时须要,有时不须要,这才是程序须要的
def zaoren(): # print('浇水') #此需求有的时候须要,有的时候不须要 print('捏个泥人') print('吹口仙气') print('就出来人了') zaoren() zaoren() zaoren()
上面的写法依然没知足咱们的需求
(2)
#三年大旱,没有水? def zaoren(): # print('浇水') #此需求有的时候须要,有的时候不须要 print('捏个泥人') print('吹口仙气') print('就出来人了') def water(): print('浇水') zaoren() zaoren() #不能一直修改这两行代码 water() #这时的设计就不符合开闭原则
(3)装饰器的源头
# # 装饰器 def wrapper(fn): # fn接收的是一个函数 def inner(): print("浇水") fn() # 调用你传递进来的函数 print("睡一觉") return inner def zaoren(): print("捏个泥人") print("吹口仙气") print("你就出来了") zaoren = wrapper(zaoren) zaoren() zaoren()
(4)lol & 消消乐
#lol def lol(): print('双击lol') print('选择狂战士') print('进草丛') print('崩山击,十字斩') #开心消消乐 def kxxxl(): print('双击消除') print('进入下一关') print('升级') print('继续玩') #开挂 #关闭外挂 def wrapper(fn): def inner(): print('开挂') fn() print('关闭外挂') return inner #lol装饰器 lol=wrapper(lol) lol() # #kxxxl装饰器 kxxxl=wrapper(kxxxl) kxxxl() ''' 结果: 开挂 双击lol 选择狂战士 进草丛 崩山击,十字斩 关闭外挂 开挂 双击消除 进入下一关 升级 继续玩 关闭外挂 '''
(5)
装饰器传参
def play(username,password): print('双击lol') print('登陆',username,password) print('选择狂战士') print('进草丛') print('崩山击,十字斩') return '十字斩刀者' def xiaoxiaole(qq): print('登陆qq帐号') print('消消乐')
开挂
关闭外挂
在目标函数前和后插入一段新的代码,不改变原来的代码
方法一:(投机版)
def wrapper(fn): #fn=play def inner(*args,**kwargs):#无敌传参 聚合接收到的是元组('alex',123) print('开挂') fn(*args,**kwargs) print('关闭外挂') return '十字斩刀者' return inner play=wrapper(play) #play=inner 左边的play表明inner w=play('alex','123') print(w) #在这里返回的是inner的return xiaoxiaole=wrapper(xiaoxiaole) xiaoxiaole(11010)
方法二:
def wrapper(fn): #fn=play def inner(*args,**kwargs):#无敌传参 聚合接收到的是元组('alex',123) print('开挂') s=fn(*args,**kwargs) #这里也有变化 print('关闭外挂') return s #这里返回的接收的是内部函数的,若是play没有返回值,返回None return inner play=wrapper(play) #play=inner 左边的play表明inner w=play('alex','123') print(w) #在这里返回的是play的return
(6)
通用装饰器写法:(写10遍以上!!!)
#python里面的动态代理 #存在的意义:在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能 #inner至关于代理 def wrapper(fn): #fn是目标函数 def inner(*args,**kwargs): #为了目标函数的传参 '''在执行目标函数以前''' ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值 '''在执行目标函数以后的操做,能够加if判断等等''' return ret #目标函数返回值返回,保证函数正常的结束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): pass #target_func=wrapper(target_func) #此时上面的fn就是target_func target_func() #此时执行的是inner # #注意:不要用打印当成返回值
3.带参数的装饰器
def wrapper_out(flag): #装饰器自己的参数 def wrapper(fn): #目标函数 def inner(*args,**kwargs): #目标函数执行须要的参数 if flag==True: 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) 返回一个装饰器wrapper 再和@拼接 @装饰器 # wrapper_out(True) # yue=wrapper(yue) #左边的yue返回值是inner,右边的yue才是真正的下面的yue def yue(): #被wrapper装饰 print('走啊,约不?') yue() #执行yue,这里的yue是指inner,
结果测试:
''' False: 走啊,约不? True: 问问金老板,最近行情怎么样啊? 走啊,约不? 金老板再骗我,恨你 '''
4.多个装饰器装饰同一个函数
def wrapper1(fn): def inner(*args, **kwargs): print("1111111") ret = fn(*args, **kwargs) print("2222222") return ret return inner def wrapper2(fn): def inner(*args, **kwargs): print("3333333") ret = fn(*args, **kwargs) print("44444444") return ret return inner def wrapper3(fn): def inner(*args, **kwargs): print("555555") ret = fn(*args, **kwargs) print("666666") return ret return inner # 就近原则 @wrapper1 @wrapper2 @wrapper3 def func(): print("我是可怜的func") func() #本身总结:把最终要执行的核心语句当成鱼的大刺对称吃鱼原则 # 1 2 3 func 3 2 1
5.装饰器的应用
menu = ("查看", "添加", "修改", "删除", "退出") flag = False # 没登陆 def login(): global flag username = input("请输入用户名:") password = input("请输入密码:") if username == "alex" and password == "123": flag = True print("登陆") else: flag = False print("用户名密码错误") # 登陆验证装饰器函数 def login_verify(fn): def inner(*args, **kwargs): # 登陆校验 while 1: if flag == True: ret = fn(*args, **kwargs) return ret else: print('对不起, 您尚未登陆') login() return inner def chakan(): print("==============================查看") @login_verify def tianjia(): print("============================添加") @login_verify def xiugai(): print("=======================修改") @login_verify def shanchu(): print("=========================删除") while 1: for i in range(len(menu)): print(i+1, menu[i]) num = input("请输入你要执行的菜单:") if num == "1": chakan() elif num == "2": tianjia() elif num == "3": xiugai() elif num == "4": shanchu() elif num == "5": print("程序退出中..........") exit() else: print("输入有误. 请从新选择!")
做业:
1.整理装饰器的造成过程, 背诵装饰器的固定格式
#装饰器通用写法 #存在的意义:在不破坏原有函数和原有函数调用的基础上,给函数添加新的功能 #inner至关于代理 def wrapper(fn): #fn是目标函数 def inner(*args,**kwargs): #为了目标函数的传参 '''在执行目标函数以前的操做''' ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值 '''在执行目标函数以后的操做,能够加if判断等等''' return ret #目标函数返回值返回,保证函数正常的结束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): # print('1') pass #target_func=wrapper(target_func) #此时上面的fn就是target_func target_func() #此时执行的是inner #注意:不要用打印当成返回值
2.编写装饰器, 在每次执行被装饰函数以前打印”
每次执行被装饰函数之前都要先通过这里, 这里根据需求添加代码”
def wrapper(fn): #fn是目标函数 def inner(*args,**kwargs): #为了目标函数的传参 '''在执行目标函数以前的操做''' ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值 return ret #目标函数返回值返回,保证函数正常的结束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): pass #target_func=wrapper(target_func) #此时上面的fn就是target_func target_func() #此时执行的是inner
3.编写装饰器, 在每次执行被装饰函数以前打印”
每次执行被装饰函数之后都要通过这里, 这里根据需求添加代码”
def wrapper(fn): #fn是目标函数 def inner(*args,**kwargs): #为了目标函数的传参 ret=fn(*args,**kwargs) #调用目标函数,ret是目标函数的返回值 '''在执行目标函数以后的操做,能够加if判断等等''' return ret #目标函数返回值返回,保证函数正常的结束 return inner @wrapper #target_func=wrapper(target_func) def target_func(): pass #target_func=wrapper(target_func) #此时上面的fn就是target_func target_func() #此时执行的是inner
4.编写装饰器, 在每次执行被装饰函数以前让用户输入用户名,
密码, 给用户三次机会, 登陆成功以后, 才能访问该函数
def login(): global flag count=1 #方法一: # while 1: # username = input("请输入用户名:") # password = input("请输入密码:") # #3次失败,直接离开整个程序 # if username == "alex" and password == "123": # flag = True #重点:登录成功以后,改变全局变量为True # print("登陆成功") #登录成功,直接进入下一步 # break # else: # flag = False # print("用户名密码错误") # if count==3: #if放在下边和上边是不同的 # exit() # count+=1 # else: # print('您已经输入错误了3次') #方法二: # while count<4: # username = input("请输入用户名:") # password = input("请输入密码:") # #3次失败,直接离开整个程序 # if username == "alex" and password == "123": # flag = True #重点:登录成功以后,改变全局变量为True # print("登陆成功") #登录成功,直接进入下一步 # break # else: # flag = False # print("用户名密码错误") # # if count==3: #if放在下边和上边是不同的 # # exit() # count+=1 # print(count) # else: # print('您已经输入错误了3次') # exit() #方法三: # for i in range(3): # username = input("请输入用户名:") # password = input("请输入密码:") # #3次失败,直接离开整个程序 # if username == "alex" and password == "123": # flag = True #重点:登录成功以后,改变全局变量为True # print("登陆成功") #登录成功,直接进入下一步 # break # else: # flag = False # print("用户名密码错误") # # if count==3: #if放在下边和上边是不同的 # # exit() # count+=1 # print(count) # else: # print('您已经输入错误了3次') # exit() flag = False # 没登陆 def wrapper(fn): #fn是目标函数 def inner(*args, **kwargs): # 登陆校验 while 1: if flag == True: #问题:函数是怎么走这块的? ret = fn(*args, **kwargs) return ret else: print('你好,请您登录!') login() return inner @wrapper #target_func=wrapper(target_func) def target_func(): print('冬瓜你好') #target_func=wrapper(target_func) #此时上面的fn就是target_func target_func() #此时执行的是inner
5.编写装饰器, 为多个函数加上认证功能(用户的帐户密码来源于文件,
用户有三次登陆的机会), 要求, 若是用户登陆成功了, 后续就不须要再次登陆了.
def login(): global flag count=1 #方法一: s=1 while s: username = input("请输入用户名:") password = input("请输入密码:") #3次失败,直接离开整个程序 with open('info', mode='r', encoding='utf-8') as f: for i in f.readlines(): t_user,t_pwd=i.split('|') if username == t_user and password == t_pwd: flag = True #重点:登录成功以后,改变全局变量为True print("登陆成功") #登录成功,直接进入下一步 # break s=0 else: flag = False print("用户名密码错误") count += 1 #注意应该在这里,把每次错误的数字+1 if count == 4: # if放在下边和上边是不同的 print('您已经输入错误了3次') exit() else: print('进入下一步') flag = False # 没登陆 def wrapper(fn): #fn是目标函数 def inner(*args, **kwargs): # 登陆校验 while 1: if flag == True: #问题:函数是怎么走这块的? ret = fn(*args, **kwargs) return ret else: print('你好,请您登录!') login() return inner @wrapper #target_func=wrapper(target_func) def target_func(): print('冬瓜你好') #target_func=wrapper(target_func) #此时上面的fn就是target_func target_func() #此时执行的是inner
6.给每一个函数写一个记录日志的功能. 功能要求: 每一次调用函数以前, 要将函数名称, 事件节点记录到log的日志中. 所需模块:import timeprint(time.strftime(“%Y-%m-%d %H:%M:%S”))