一、nonlocal关键字
1、作用:将L与E(E中的名字需要提前定义)的名字统一
2、应用场景:如果想在被嵌套的函数中修改外部函数变量(名字)的值
def outer():
num=10
print(num) # 输出结果为10
def inner():
nonlocal num
num=20
print(num) #输出级结果为20
inner()
print(num) # 输出结果为20
def outer(): num=0 # 必要写 是用于L与E的名字统一 def inner(): # 如果想被嵌套的函数中修改外部函数变量(名字)的值 nonlocal num # 将L与E(E中的名字需提前定义好)的名字统一 num=10 print(num) # 输出结果为10 inner() print(num ) # 定义了nonlocal就是局部统一,输出结果为10 outer() # print(num)# 属于全局,不能看到其值
二、开放封闭原则
1、原则: 不能修改被装饰对象(函数)的源代码——封闭
不能更改被修饰对象(函数)的调用方式,且能达到增加功能的效果——开放
1.0版本 def fn(): print('fn run ') fn() 版本2.0 def fn2(): print('fn run 0') print('fn run1') print('fn run2') 修改了源代码,没有更改调用方式,对外调用方式还是原来的, def fn(): print('fn run0') print('fn run ') print('fn run2') 更改了调用方式,没有修改原功能代码块 def wrap(fn): print('fn run0') fn() print('fn run2') wrap(fn)
三、装饰器
1、定义:就是闭包(闭包的一个应用场景)
把要装饰的函数作为外部函数的参数通过闭包操作返回一个替代版函数1
2、优点:丰富了原有函数的功能
提高了程序的可拓展性
把要被装饰的函数作为外层函数的参数通过闭包操作后返回一个替代版函数
被装饰的函数:fn
外层函数:outer(func)、outer(fn)==》func=fn
替代版函数;return inner:原有功能加新功能
def fn():
print('原有功能')
# 装饰器
def outer(tag):
def inner():
tag()
print('新增功能')
return inner
fn=outer(fn)
fn()
案例 花瓶 def vase(): print('插花') vase() 增加一个绘画后观赏功能 def wrap(fn): vase() print('插花') print('绘画:进行观赏') wrap(vase) 虽然满足了开放封闭原则,但出现了函数调用死循环 def fn(): vase() print('绘画:进行观赏') vase=fn() vase() 了解:满足开放fengbiyuanze,且可以达到装饰器的作用:拓展功能 tag=vase # 暴露在全局:
def fn(): tag() print('绘画:进行观赏') vase=fn vase() 满足开放封闭原则(完美方法) 方式一 def wrap (tag): tag=vase def fn(): tag() print('绘画:进行观赏') return fn # 拓展功能后的vase
vase =wrap() # 相当于vase=fn
vase() 方式二、这个函数嵌套结构就是装饰器 def wrap (tag): def fn(): tag() # 指原有的vase
print('绘画:进行观赏') return fn # 拓展功能后的vase
vase =wrap(vase) # 将拓展功能后的函数重新赋值给vase
vase() # 功能拓展了,且调用方式不变
四、装饰器的简化语法
ef outer(f): def inner(): f() print("新增功能1") return inner def wrap(f): def inner(): f() print("新增功能2") return inner @wrap # 被装饰的顺序决定了新增功能的执行顺序
@outer # <==> fn = outer(fn): inner
def fn(): print("原有功能")
案例: def outer (fn): def inner(): fn() print('绘画:进行观赏') return inner def wrse (fn): def inner(): fn() print('摆放功能') return inner @语法糖|笑笑语法 @wrse @outer #等于这个功能<==>vase =outer(vase)
def vase(): print('插花') vase() 总结:一个函数可以被任意一个相关装饰器装饰,也可以被任意几个装饰器装饰 注:装饰的顺序会影响新增功能的执行顺序
五、有参有返的函数被修饰
def check_usr(fn):# fn,login,inner:不同状态下的login,所以参数是统一的 def inner(usr,pwd): # 在原功能上添加新功能 if not(len(usr)>=3and usr.isalpha()): print('账号验证失败') return False # 原有功能 result=fn(usr,pwd) # 在原功能下添加新功能 #。。。。。()没有添加则用句号省略了 return result return inner @check_usr def login(usr,pwd): if usr=='abc'and pwd=='123abc': print('登录成功') return True print('登录失败') return False
总结:1、login有参数,所以inner与fn都有相同参数
2、login有返回值,所以inner与fn都有返回值
inner(usr, pwd):
res = fn(usr, pwd) # 原login的返回值
return res
login = check_usr(login) = inner
res = login('abc', '123qwe') # inner的返回值
案例: 增加一个账号处理功能:3位以上英文字符或汉字
def check_usr(fn): def inner(usr,pwd): if not (len(usr)>=3 and usr.isalpha()): print('账号验证失败') return False result=fn(usr,pwd) #login
return result return inner 增加一个密码处理功能:6位以上英文和数字 def check_pwd(fn): def inner(usr,pwd): if not (len(pwd)>=6 and pwd.isalnum()): print('密码验证失败') return False return fn(usr,pwd) #result=fn(usr,pwd) return result
return inner 登录功能 @check_usr # login=check_usr(login)=inner
def login(usr,pwd): if usr=='abc' and pwd=='123abc': print('登录成功') print('登录失败') return False res=login('abc','123abc') # inner 用户名和密码正确输出验证成功
print(res)
六、装饰器的最终写法
# 装饰器的最终写法
def wrap (fn): def inner(*args,**kwargs): print('前增功能') result =fn(*args,**kwargs) print('后增功能') return result return inner @wrap def fn1(): print('fn1的原有功能') @wrap def fn2(a,b): # 有参数无值
print('fn2的原有功能') @wrap def fn3():# 有返回值无参数
print('fn2的原有功能') return True @wrap def fn4(a,*,c): #有参数有返回值
print('fn2的原有功能') return True fn1() fn2(10,20) fn3() fn4(10,c=20) 案例: 增加一个账号处理功能:3位及以上英文字符或汉字 def check_usr(fn): def inner(usr,pwd): if not(len(usr)>=3 and usr.isalpha()): print('账号验证失败') return False result=fn(usr,pwd) #login
return result return inner 登录功能 @check_usr def login(usr,pwd): if usr=='abc'and pwd=='123abc': print('登录成功') return True print('登录失败') return False res=login('abc','123abc') #inner 账号密码正确打印成功
print(res)
带参装饰器 def outer(input_color): def wrap(fn): if input_color=='red': info='\033[36;41m new action\33[0m'
else: info='yellow:new action'
def inner(*args,**kwargs): pass result=fn(*args,**kwargs) print(info) return result return inner return wrap #outer(color)=>>wrap
color=input('color:') def func(): print('func run') func()
七、登录认证案例
is_login=False #登录状态
def login(): usr=input('usr:') if not(len(usr)>=3 and usr.isalpha()): print('账号验证失败') return False pwd=input('ped:') if usr=='abc'and pwd=='123abc': print('登录成功') is_login=True else: print('登录失败') is_login=False 完成一个登录状态校验的装饰器 def check_login(fn): def inner(*args,**kwargs): # 查看个人主页或销售功能前:如果没有登录需要先登录,繁殖可以进入其功能
if is_login!=True: print('你未登录') login() # 查看个人主页或销售
result=fn(*args,**kwargs) return result 查看个人主页功能 @check_login def home(): print('个人主页') 销售功能 @check_login def sell(): print('可以销售') home()