#python #functools
Вопрос:
Я действительно недостаточно (пока) знаю о python, чтобы разобраться в этом самостоятельно, поэтому я хотел попробовать здесь. Есть ли какой-нибудь способ сделать так, чтобы эти почти идентичные функции @wraps занимали меньше места? Всего у меня их 5, и 100 строк для 5 раз одно и то же звучит как пустая трата времени. Первоначально я нашел это на каком-то веб-сайте, но, похоже, больше не могу найти.
Функции:
def a_required(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if request.method in EXEMPT_METHODS:
return func(*args, **kwargs)
elif current_app.config.get('LOGIN_DISABLED'):
return func(*args, **kwargs)
elif not current_user.is_authenticated or not current_user["Keys"]["A"]:
return current_app.login_manager.unauthorized()
return func(*args, **kwargs)
return decorated_view
def b_required(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if request.method in EXEMPT_METHODS:
return func(*args, **kwargs)
elif current_app.config.get('LOGIN_DISABLED'):
return func(*args, **kwargs)
elif not current_user.is_authenticated or not current_user["Keys"]["B"]:
return current_app.login_manager.unauthorized()
return func(*args, **kwargs)
return decorated_view
Это для веб-сайта Flask, страницы которого будут доступны только пользователям с соответствующими правами.
Комментарии:
1. Вы можете написать функцию «более высокого порядка», которая возвращает такую функцию декоратора, но с ключом (a, b,…), о котором идет речь, в качестве параметра внешней функции.
2. Не могли бы вы привести пример?
Ответ №1:
Вы можете написать функцию, которая возвращает декоратор, и назвать ее так:
def required(req):
def wrapper(func):
@wraps(func)
def decorated_view(*args, **kwargs):
# put your decorated_view code here
# swapping out the hard coded `current_user["Keys"]["B"]`
# for `current_user["Keys"][req]`
print("executing decorator with", req)
return func(*args, **kwargs)
return decorated_view
return wrapper
@required("B")
def foo():
print("inside foo function")
@required("A")
def bar():
print("inside bar function")
Тогда выполнение этих функций выглядит следующим образом:
>>> foo()
executing decorator with B
inside foo function
>>> bar()
executing decorator with A
inside bar function
Функция required
возвращает динамический декоратор, который изменяет свое поведение в зависимости от значения req
, которое мы ему передаем. Таким образом, decorated_view
функция может получить доступ к соответствующему значению req
в зависимости от того, как мы вызвали required(...)
.
Комментарии:
1.
nonlocal
Заявление здесь не требуется, так как вы не пишетеreq
.2. хорошая мысль, я удалил ее из фрагмента.
Ответ №2:
попробуйте это:
def required(req):
def wrapper(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if not current_user.is_authenticated or not current_user["Keys"][req]:
return current_app.login_manager.unauthorized()
return func(*args, **kwargs)
return decorated_view
return wrapper
@required("A")
def method1():
pass
@required("B")
def method2():
pass