了解functools.wraps

时间:2013-04-09 04:29:37

标签: python

我正在使用Flask-RESTful并尝试使用显示here

的技术来获取我的REST端点

主要代码是

def authenticate(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        if not getattr(func, 'authenticated', True):
            return func(*args, **kwargs)

        acct = basic_authentication()  # custom account lookup function

        if acct:
            return func(*args, **kwargs)

        restful.abort(401)
    return wrapper


class Resource(restful.Resource):
    method_decorators = [authenticate]   # applies to all inherited resources

我以同样的方式行事似乎有效,但我不确定@wraps会发生什么? 这对我来说似乎很神奇,我不理解以下

a。)似乎用@wraps包装的函数传递给包装器,然后包装器返回什么?

可能的答案:最初传递给函数的所有内容?

如果是,我怎样才能将acct对象等更多信息传递给所有内容,以便我的函数收到帐户对象而我不必为它进行数据库获取?

更新 根据示例,我的休息端点看起来像

class UserResource(RestResource):
    def get(self, uuid):
        return {'method': 'get user -> ' + uuid}

我称之为

curl -X GET http://127.0.0.1:5000/users/validUUID

现在,当我的每个请求都经过身份验证时,我会看到是否存在有效的acct对象,如果它存在,我将控件委托给端点

问题
由于我实际上正在进行一次数据库调用以找出acct对象,因此当找到有效的acct时是否可以将其传递给端点?

这样就会发生两件事情 a。)我知道通话已通过身份验证 b。)我重用了我可用于进一步工作的acct对象,而不是再次调用DB并再次从validUUID获取acct对象

我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:3)

authenticate是一个装饰器 - 它接受一个函数并返回该函数的修改版本(通常通过包装函数并将其包装来实现)。

现在,包装器的问题在于它们通常在某些方面与原始函数完全不同 - 它们可能缺少文档字符串,错误__name__wrapper而不是什么它应该被称为)和其他瑕疵。如果其他一些代码正在使用该额外信息,这可能很重要。 functools.wraps是一个简单的函数,它将原始函数(此处为func)中的此信息添加到包装函数中,因此它的行为更像原始函数。 (从技术上讲,它本身就是一个装饰器,这是一个令人困惑的部分,但你不必担心这个细节。只要知道它是一个很好的工具,将包装函数的属性复制到包装函数。)

因此,当你写

new_function = authenticate(old_function)

或更常见

@authenticate
def function(...)

new_function看起来更像old_function