1、反面教材
# TODO make an order
def ordering():
# 第一验证 验证是否登录
# 第二验证 验证是否具有权限
print('————————正在下订单————————')
# TODO change password
def changepwd():
# 第一验证 验证是否登录
# 第二验证 验证是否具有权限
print('————————修改密码————————')
# TODO show your personal info
def showinfo():
# 第一验证 验证是否登录
# 第二验证 验证是否具有权限
print('————————个人信息————————')
可以看到我们在进行下订单,修改密码或是查询自己的信息时都需要在登录,并且具有相应权限的情况下进行。
但是我们不可能在每个函数里都写这样的两个函数。因为代码会变得冗余。
所以这里就用到了装饰器。但装饰器是基于闭包的。所以先来了解闭包。
2、闭包(提高函数的重用性)
一个函数嵌套另一个函数,内部的函数使用到了外部的函数的变量
def wrapper(num1):
def inner(num2):
return num1 + num2
return inner
if __name__ == '__main__':
func = wrapper(1)
print(func(2))
打印输出:3
闭包实现一个二元一次直线方程
def wrapper(k,b):
def inner(x):
return x*k + b
return inner
if __name__ == '__main__':
func = wrapper(1,1)
print(func(2))
打印输出:3
缺点:一直引用外部函数的变量而不释放,容易消耗内存
3、正面教材
3.1 方法一:
def wrapper(func): # func被装饰的函数的引用
def inner():
# 第一验证 验证是否登录
# 第二验证 验证是否具有权限
print("我是装饰器")
func() # 调用函数
return inner # 不带括号,因为返回函数的引用,而不是调用函数
def changepwd():
print('————————修改密码————————')
if __name__ == '__main__':
MyFunc = wrapper(changepwd) # 引用
MyFunc()
输出打印:我是装饰器
————————修改密码————————
3.2 方法二:
def wrapper(func): # func被装饰的函数的引用
def inner():
# 第一验证 验证是否登录
# 第二验证 验证是否具有权限
print("我是装饰器")
func() # 调用函数
return inner # 不带括号,因为返回函数的引用,而不是调用函数
@wrapper
def changepwd():
print('————————修改密码————————')
if __name__ == '__main__':
changepwd()
打印输出:我是装饰器
————————修改密码————————
给函数添加上了@wrapper,使得函数具备新的功能。
3.3 多层包裹
def wrapper1(func): # func被装饰的函数的引用
print('begin wrapper1')
def inner(): # 调用参数用inner
print(1)
func()
print('end wrapper1')
return inner
def wrapper2(func):
print('begin wrapper2')
def inner():
print(2) # print要写在func()之前!!!
func()
print('end wrapper2')
return inner
@wrapper2
@wrapper1 # 结合性自下而上,执行性自上而下
def changepwd():
print('--------修改密码-----------')
直接执行,不调用,可以看到
begin wrapper1
end wrapper1
begin wrapper2
end wrapper2
wrapper1先,这就是装饰的结合性,自下而上
if __name__ == '__main__':
changepwd()
加上执行,可以看到
begin wrapper1
end wrapper1
begin wrapper2
end wrapper2
2
1
--------修改密码-----------
先执行wrapper2,这就是执行性,自上而下
3.4 带参数的函数装饰
def wrapper(func): # 装饰器要写在函数上面,函数才能使用
def inner(*args):
func(args[0],args[1])
print("{}块钱用完了,蛋糕还不好吃……{}".format(args[0],args[1]))
return inner
@wrapper
def cost(money,status):
print("买买买了%d块钱的蛋糕"%money)
if __name__ == '__main__':
cost(10,"不开心不开心呢")
3.4 装饰工厂
三层嵌套
def create():
def wrapper(func):
def inner():
func()
return inner
return wrapper
==========三层可实现装饰器带参数=======
def create(arg1, arg2):
def wrapper(func):
def inner(x):
func(x)
print(arg1, arg2)
return 4
return inner
return wrapper
@create(5, 6)
def calc(x):
print('ok%s'%x)
ret = calc(3)
print(ret)
ok3
5 6
4
4、总结:
装饰器的应用场景:
1.减少冗余代码,提高函数的重用性
2.增加额外功能
缺点:一直引用外部函数的变量而不释放,容易消耗内存