funtools.wraps
Posted 哦...
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了funtools.wraps相关的知识,希望对你有一定的参考价值。
当我们写装饰器的时候,有一个潜在的问题:
def login_require(func):
def wrapper(*args,**kwargs):
print("check...")
print("check finished")
func(*args,**kwargs)
print("done")
return wrapper
@login_require
def index():
print(f"hello world")
@login_require
def login(name):
print(f"hello name")
print(index.__name__)
print(login.__name__)
此时执行的结果是:
wrapper
wrapper
原因大家都知道,@装饰器是一种语法糖的格式。执行index.__name__时,实际执行的是login_require(index).__name__,那显然这个值就是wrapper。login.__name__的值也是同理。
其实这在很多场合使用是没有问题的,但是在某些特别需要独一无二函数名称的场景就会出现问题了,比如Flask的视图函数。
在Flask跳转界面的时候经常会出现如下的跳转代码:
if request.method=="POST":
业务逻辑
return redirect(url_for("login"))
return reder_template("xxx.html")
url_for是根据视图函数查找资源路径,然后进行跳转,换句话说视图函数与资源路径要一一对应。但是如果现在的视图函数是:
@app.route("/xxx")
@login_require
def xxx():
return "hello xxx"
@app.route("/yyy")
@login_require
def yyy():
return "hello yyy"
这样写就意味着/xxx和/yyy的视图函数对应的视图函数均为wrapper,违反了一一对应的原则。
处理方式有两种:
第一种:注意装饰器的书写顺序
@login_require
@app.route("/xxx")
def xxx():
return "hello xxx"
@login_require
@app.route("/yyy")
def yyy():
return "hello yyy"
第二种:使用functools.wraps,还被装饰函数的本来名称:
def login_require(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
print("check login...")
func(args,kwargs)
return wrapper
@app.route("/xxx")
@login_require
def xxx():
return "hello xxx"
@app.route("/yyy")
@login_require
def yyy():
return "hello yyy"
在login_require中对内部函数加上装饰器@functools.wraps(func),这样就能保证被装饰的函数依然保留自己的函数名称。这样/xxx对应的视图函数名称是xxx,而/yyy对应的视图函数名称是yyy,就不存在重名问题了。
以上是关于funtools.wraps的主要内容,如果未能解决你的问题,请参考以下文章