Вы возвращаете outer
, не вызывая его, в результате вызова представления . Таким образом, Flask должен обработать этот как ответ представления , а ответ, который не является строкой, кортежем или Response
, рассматривается как объект WSGI. Обычный способ обработки ответа WSGI - вызвать его как <wsgi response>(environment, start_response)
.
Вам необходимо вернуть фактический результат вызова outer()
.
Вот что происходит во время импорта модуля:
def login(): ...
выполняется, создается объект функции login
.
@conditional
применяется в качестве декоратора для login
.
def inner(): ...
выполняется, создавая вложенную функцию с func
в ее закрытии. Декоратор @wraps(func)
присоединяет имя func
к inner
return inner
возвращает inner
вызывающей стороне
login = inner
устанавливается в результате `@ conditional
- @app.route ()
registers
внутренний as the route handler for
/ login`
Вот что происходит, когда вы получаете доступ к /login
по HTTP:
- Flask ищет функцию просмотра для
/login
, находит inner
, вызывает ее
- Тест
if condition:
неверен, перейдите к следующему разделу
decorator(1, 2)
называется
def wrapped(func): ...
выполняется, создавая внутреннюю функцию с foo
и bar
в замыкании
return wrapped
возвращает звонящему
decorator(1, 2)...
- это wrapped...
, поэтому wrapped(func)
называется
def outer(): ...
выполняется, создает внутреннюю функцию с func
в ее закрытии. Декоратор @wraps(func)
присоединяет имя func
к inner
.
return outer
возвращает функцию outer
вызывающей стороне.
outer
возвращается вызывающей стороне
- Flask дается
outer
в качестве ответа, который обрабатывается как объект WSGI.
Вы пропускаете последний звонок здесь:
def conditional(func):
@wraps(func)
def inner():
if some_condition:
raise Error
return decorator(1, 2)(func)() # call the decorated `func()`
return inner
Однако, если вы не хотите, чтобы условие препятствовало применению вызова decorator(1, 2)
, вы хотите сохранить результат decorator(1, 2)(func)
вместо того, чтобы декорировать его для каждого вызова:
def conditional(func):
func = decorator(1, 2)(func)
@wraps(func)
def inner():
if some_condition:
raise Error
return func()
return inner
Срединной точкой может быть вызов только decorator(1, 2)
один раз, для создания реальной функции декоратора, один раз:
def conditional(func):
dec = decorator(1, 2)
@wraps(func)
def inner():
if some_condition:
raise Error
return dec(func)()
return inner
Наконец, рассмотрите возможность передачи аргументов, переданных в inner()
, функции декорированного представления, чтобы вы могли использовать @condition
в функциях представления, которые принимают параметры маршрута:
def conditional(func):
@wraps(func)
def inner(*args, **kwargs):
if some_condition:
raise Error
return decorator(1, 2)(func)(*args, **kwargs)
return inner