4.02Day12函数 装饰器

一、nonlocal关键字
作用:将 L 与 E 中的名字统一,L中的名字需要先定义

应用场景:在被嵌套函数中修改函数外的值

案例:
def outer():
x = 10
print(x) # x = 10
def inner():
nonloacl x
x = 20
print(x) # x = 20

inner()
print(x) # x = 20



二、开放封闭原则
1.不能修改被装饰对象(函数)的源代码(封闭)
2.不能更改被修饰对象(函数)的调用方式,且能达到增加功能的效果(开放)

三、装饰器
要把被装饰的函数作为外层函数的参数,通过闭包操作后返回一个替代版函数
被装饰的函数:fn
外层函数:outer(func) outer(fn) => func = fn
替代版函数:return inner : 原功能 + 新功能

def fn():
print('原有功能')


# 装饰器
def outer(tag): # tag为被装饰函数的内存地址
def inner():
print(新增功能")
tag() # 将被被装饰函数的内存地址 传值给tag ,再形成tag()调用原函数
return inner

fn = outer(fn) # outer()为函数outer的return值,
fn() # fn() == inner() 就是 函数outer的ruturn值--函数 inner的内存地址加上()之后 调用

四:语法糖 @外层函数
def outer(f):
def inner():
f() # 通过参数传递原函数内存地址的方式来调用原函数
print("新增功能1")
return inner

def wrap(f):
def inner():
f() # 通过参数传递原函数内存地址的方式来调用原函数
print("新增功能2")
return inner

@wrap # 被装饰的顺序决定了新增功能的执行顺序 ==> fn = wrap(fn): inner
@outer # ==> fn = outer(fn): inner
def fn():
print("原有功能")

五、有参有返的函数被装饰
def check_usr(fn): # fn, login, inner:不同状态下的login,所以参数是统一的

def inner(usr, pwd):
if not (len(usr) >= 3 and usr.isalpha()): # 在原功能上添加新功能
print('账号验证失败')
return False
result = fn(usr, pwd) # 原有功能
# 也可以在原功能下添加新功能
return result

return inner


@check_usr # 语法糖
def login(usr, pwd):
if usr == 'abc' and pwd =='123qwe':
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的返回值

六、装饰器最终写法
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('fn3的原有功能')
return True
@wrap
def fn4(a, *, x):
print('fn4的原有功能')
return True

fn1()
fn2(10, 20)
fn3()
fn4(10, x=20)

七、带参装饰器:了解
# 了解
def outer(input_color):
def wrap(fn):
if input_color == 'red':
info = '\033[36;41mnew 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: ')
@outer(color) # @outer(color) ==> @wrap # func => inner
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('pwd: ')
if usr == 'abc' and pwd =='123qwe':
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
return inner

# 查看个人主页功能
@check_login
def home():
print('个人主页')

# 销售功能
@check_login
def sell():
print('可以销售')

home()
posted @ 2019-04-02 15:35  输诚  阅读(87)  评论(0编辑  收藏  举报