将两个 python 装饰器合二为一
Posted
技术标签:
【中文标题】将两个 python 装饰器合二为一【英文标题】:Combine two python decorators into one 【发布时间】:2013-06-09 21:32:55 【问题描述】:这里有两个装饰器我想组合起来,因为它们非常相似,不同之处在于如何处理未经过身份验证的用户。我希望有一个可以用参数调用的装饰器。
# 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=01'.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
目前我正在将这些装饰器用于特定路线,例如
@get('/day/')
@helpers.requireAuthentication
def day():
...
@get('/night/')
@helpers.requireAuthenticationJSON
def night():
...
我更喜欢这个:
@get('/day/')
@helpers.requireAuthentication()
def day():
...
@get('/night/')
@helpers.requireAuthentication(json = True)
def night():
...
我在 python 3.3 上使用 Bottle 框架。有可能做我想做的事吗?怎么样?
【问题讨论】:
【参考方案1】:您可以为这两个装饰器创建包装器:
def requireAuthentication(json=False):
if json:
return helpers.requireAuthenticationJSON
else:
return helpers.requireAuthentication
或者
import functools
# Authentication decorator for routes
# Will redirect to the login page if not authenticated
def requireAuthentication(json=False):
def requireAuthentication(fn):
@functools.wraps(fn)
def decorator(*args, **kwargs):
# Is user logged on?
if "user" in request.session:
return fn(*args, **kwargs)
if json:
return
"exception": "NotAuthorized",
"error" : "You are not authorized, please log on"
return redirect('/login?url=01'.format(request.path,
("?" + request.query_string if request.query_string else '')))
return decorator
return requireAuthentication
【讨论】:
【参考方案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=01'.format(request.path, ("?" + request.query_string if request.query_string else '')))
return wrapper
return decorator
我已将您原来的 requireAuthentication
函数重命名为 decorator
(因为这是该函数所做的,它装饰了 fn
)并将旧的 decorator
重命名为 wrapper
,这是通常的约定。
无论你把什么放在之后,@
都是一个表达式,首先求值以找到实际的装饰器函数。 @helpers.requireAuthentication()
表示您要调用 requireAuthentication
并且它的 返回值 然后用作 @
行适用的函数的实际装饰器。
【讨论】:
以上是关于将两个 python 装饰器合二为一的主要内容,如果未能解决你的问题,请参考以下文章