将两个 python 装饰器合二为一

And*_*eas 5 python decorator bottle python-3.x python-decorators

这是我想组合的两个装饰器,因为它们非常相似,区别在于如何处理未经身份验证的用户。我更喜欢有一个可以通过参数调用的装饰器。

# Authentication decorator for routes
# Will redirect to the login page if not authenticated
def requireAuthentication(fn):
    def decorator(**kwargs):
        # Is user logged on?
        if "user" in request.session:
            return fn(**kwargs)
        # No, redirect to login page
        else:
            redirect('/login?url={0}{1}'.format(request.path, ("?" + request.query_string if request.query_string else '')))
    return decorator

# Authentication decorator for routes
# Will return an error message (in JSON) if not authenticated
def requireAuthenticationJSON(fn):
    def decorator(**kwargs):
        # Is user logged on?
        if "user" in request.session:
            return fn(**kwargs)
        # No, return error
        else:
            return {
                "exception": "NotAuthorized",
                "error" : "You are not authorized, please log on"
            }
    return decorator
Run Code Online (Sandbox Code Playgroud)

目前我正在将这些装饰器用于特定路线,例如

@get('/day/')
@helpers.requireAuthentication
def day():
    ...

@get('/night/')
@helpers.requireAuthenticationJSON
def night():
    ...
Run Code Online (Sandbox Code Playgroud)

我更喜欢这个:

@get('/day/')
@helpers.requireAuthentication()
def day():
    ...

@get('/night/')
@helpers.requireAuthentication(json = True)
def night():
    ...
Run Code Online (Sandbox Code Playgroud)

我使用 Bottle 框架使用 python 3.3。可以做我想做的事吗?如何?

Mar*_*ers 2

只需添加另一个包装器来捕获json参数:

def requireAuthentication(json=False):
    def decorator(fn):
        def wrapper(**kwargs):
            # Is user logged on?
            if "user" in request.session:
                return fn(**kwargs)

            # No, return error
            if json:
                return {
                    "exception": "NotAuthorized",
                    "error" : "You are not authorized, please log on"
                }
            redirect('/login?url={0}{1}'.format(request.path, ("?" + request.query_string if request.query_string else '')))
        return wrapper
    return decorator
Run Code Online (Sandbox Code Playgroud)

我已将您的原始requireAuthentication函数重命名为decorator(因为这就是该函数所做的,它装饰了fn)并将旧函数重命名decoratorwrapper通常的约定。

无论您在the之后@放置什么,都是一个表达式,首先评估以找到实际的装饰器函数。@helpers.requireAuthentication()意味着您要调用requireAuthentication,然后将其返回值用作该行@适用的函数的实际装饰器。