我希望只有登录用户具有所需的权限级别才能执行不同的功能。
为了让我的生活更复杂,我只想使用装饰器。下面我尝试在'装饰'函数上设置属性permission
- 如下所示。
def permission(permission_required):
def wrapper(func):
def inner(*args, **kwargs):
setattr(func, 'permission_required', permission_required)
return func(*args, **kwargs)
return inner
return wrapper
@permission('user')
def do_x(arg1, arg2):
...
@permission('admin')
def do_y(arg1, arg2):
...
但是当我这样做时:
fn = do_x
if logged_in_user.access_level == fn.permission_required:
...
我收到错误'function' object has no attribute 'permission_required'
我错过了什么?
答案 0 :(得分:17)
您正在内部(包装器)函数中设置属性。您根本不需要包装函数 :
def permission(permission_required):
def decorator(func):
func.permission_required = permission_required
return func
return decorator
你的装饰者需要返回某些东西,它将取代原来的功能。原始函数本身(添加了属性)可以正常使用,因为你想要做的就是为它添加一个属性。
如果您仍需要包装器,请在包装函数上设置属性:
def permission(permission_required):
def decorator(func):
def wrapper(*args, **kwargs):
# only use a wrapper if you need extra code to be run here
return func(*args, **kwargs)
wrapper.permission_required = permission_required
return wrapper
return decorator
毕竟,您正在使用装饰器返回的包装器替换包装函数,因此这是您要查找属性的对象。
答案 1 :(得分:1)
你的装饰者应该返回一个可以替换do_x
或do_y
的函数,而不是返回do_x
或do_y
的执行结果
你可以修改你装饰如下:
def permission(permission_required):
def wrapper(func):
def inner():
setattr(func, 'permission_required', permission_required)
return func
return inner()
return wrapper
当然,您还有另一个简短的解决方案:
def permission(permission_required):
def wrapper(func):
setattr(func, 'permission_required', permission_required)
return func
return wrapper
答案 2 :(得分:0)
问题在于,即使您在inner
中为包装的函数设置了所需的属性,inner
仍会返回修饰后的函数返回的内容,而函数本身通常不会返回。
您应该只返回与添加属性相同的原始函数,因此,您不必担心此原始装饰函数可能采用的参数,这意味着您可以摆脱包装级别之一:
def permission(permission_required):
def wrapper(func):
setattr(func, 'permission_required', permission_required)
return func
return wrapper
@permission('user')
def do_x(arg1, arg2):
pass
@permission('admin')
def do_y(arg1, arg2):
pass
这很好用:
>>> do_x
<function __main__.do_x(arg1, arg2)>
>>> do_x.permission_required
'user'
>>> do_y.permission_required
'admin'