декоратор для установки атрибутов функции

Я хочу, чтобы разные функции исполнялись только в том случае, если зарегистрированный пользователь имеет необходимый уровень разрешений.

Чтобы сделать мою жизнь более сложной, я просто хочу использовать декораторов. Ниже я могу установить 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'

Что мне не хватает?

2 Solutions collect form web for “декоратор для установки атрибутов функции”

Вы устанавливаете атрибут во внутренней (обертке) функции. Вам вообще не нужна функция обертки:

 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 

В конце концов, вы заменяете завернутую функцию оболочкой, возвращаемой декоратором, так что это объект, на который вы будете искать атрибут.

Ваш декоратор должен возвращать функцию, которая может заменить do_x или do_y , а не возвращать результат выполнения do_x или do_y Вы можете do_x do_y как 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 
Python - лучший язык программирования в мире.