装饰器的作用:在不改变原函数的情况下给函数增加功能!
装饰器由闭包和语法糖组成
闭包:即两个函数嵌套,外部函数返回内部函数的引用,外部函数一定会传入参数,外部函数起的是交换引用的作用:把要装饰的参数(也就是装饰前的函数)与 装饰后的函数的引用对换,而里层的函数做的是执行操作,调用原函数就是在这里执行的!
#闭包模型
#外函数
def set_fun(func):
def call_fun( *args, **kwargs):
#里函数
#。。这里可作为要执行原函数前执行的代码段,比如验证功能。。
result = func(*args, **kwargs)
#这里可以对原函数的执行结果做筛选
return result
return call_fun
2.语法糖:
@set_fun # @这个就是语法糖,可以理解为:set_fun ===>test = set_fun(test)
def test():
print("啦啦啦!我是要装饰的原函数!^_^")
#下面说一种特殊三重装饰器,也就是给装饰器传参
def set_args(args):
print("args%s"%str(args))
def set_fun(func):
print("set_fun")
def call_fun(*args,**kwargs):
print("call_fun")
return func(*args,**kwargs)
return call_fun
return set_fun
@set_args(123) # 1.set_args(123) 2. @set_fun====>test = set_fun(test)
def test():
print("test is show")
test()
装饰器的应用场景很多:比如python里的定义类方法和静态方法就是用的装饰器:
class A(object):
@classmethod
def show_a(self):
pass
@staticmethod
def show_b():
pass
还有就是Django与flask的网页路由也是用的装饰器的原理去实现:
@api.route('/send_sms_code',methods=["POST"])
pass
下面说一下装饰器在一种特殊的情况下:
我曾经在一个flask的项目的时候出现过一个异常,那时候我写了一个装饰器去处理多个视图函数的效验登陆状态的问题,然后出现了一个异常:
AssertionError: View function mapping is overwriting an existing endpoint function: api_1_0.wraaper
这个异常出现的原因是因为一个模块下的多个视图函数同时使用这个装饰器,然后这几个视图函数之间的数据产生了互相影响,最后我用functools模块下的wraps去消除这种影响!
from functools import wraps
def login_required(view_func):
"""自定义装饰器判断登陆状态
使用装饰器装饰函数时,会修改被装饰的函数的__name属性和被装饰的函数的说明文档
为了不让装饰器影响被装饰的函数的默认的数据,我们会使用@wraps装饰器,提前对view_funcJ进行装饰
"""
@wraps(view_func)
def wraaper(*args, **kwargs):
"""判断用户登录的逻辑"""
user_id = session.get('user_id')
if not user_id:
return jsonify(code=RET.SESSIONERR, codermsg='用户未登录')
else:
g.user_id = user_id
# 执行被装饰的视图函数
return view_func(*args, **kwargs)
return wraaper
装饰器我在很多第三方的源码里都看到它的身影,它的强大可见一斑!