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的主要内容,如果未能解决你的问题,请参考以下文章

powershell windowsのubuntuなどを导入した场合にエラーが出る场合の対处

步进电机应用场合

“匿名内部类”的使用场合举例

python @classmethod 的使用场合

ES6调用 Iterator 接口的场合有哪些?

ES6调用 Iterator 接口的场合有哪些?