python的functools模块,wraps探讨

参考资料:https://www.bilibili.com/video/av15904918/

从书中看到了一段代码,对其中的含义并不是很理解。代码如下

from functools import wraps #作用于函数或者返回其它函数的函数
from flask import abort
from flask_login import current_user
from .models import Permission
#检查常规权限
def permission_required(permission):
    def decorator(f):
        @wraps(f)
        def decorated_funcation(*args,**kwargs):
            #调用can方法,检验用户的权值是否相等,来判断是否有权限
            if not current_user.can(permission):
                #abort用于提前退出,用于指定错误码的返回
                abort(403)
            return f(*args,**kwargs)
        return decorated_funcation
    return decorator

#检查管理员权限
def admin_required(f):
    #调用检查权限的函数,传入参数设置为管理员的
    return permission_required(Permission.ADMIN)

其中使用了装饰器,这一个知识点,于是便搜索了一下为什么这一段代码要用到functools.wraps,具体可以解决那些问题

结果如下

最开始实现的装饰器有几个缺点:不支持关键字参数,而且会遮盖被装饰函数的__name____doc__属性

例如:

def noop(f):
	def wrapper():
		return f()
	return wrapper

@noop
def hello():
    print("Hello,world")
 
help(hello)
print(hello.__name__)
print(hello.__doc__)

#输出
Help on function wrapper in module __main__:

wrapper()

wrapper
None

可以看到help(hello),输出来的function并不是hello的,而是wrapper。同时hello的__name__也并不是hello的。

可以通过手动修改来解决这个问题

def noop(f):
	def wrapper():
		return f()
	wrapper.__name__ = f.__name__
	wrapper.__doc__ = f.__doc__
	return wrapper

这个时候,再进行输出一次。

help(hello)
print(hello.__name__)
print(hello.__doc__)

#输出
Help on function hello in module __main__:

hello()

hello
None

但是再一个较大的项目中,这样操作,未免过于繁琐,所以这个时候可以使用functools.wraps来解决这个问题

from functools import wraps

def noop(f):
    @wraps(f)
    def wrapper():
        return f()
    return wrapper

@noop
def hello():
    print("Hello,world")

help(hello)
print(hello.__name__)
print(hello.__doc__)

#输出
Help on function hello in module __main__:

hello()

hello
None