Порядок выполнения декоратора
def make_bold(fn):
return lambda : "<b>" + fn() + "</b>"
def make_italic(fn):
return lambda : "<i>" + fn() + "</i>"
@make_bold
@make_italic
def hello():
return "hello world"
helloHTML = hello()
Выход: "<b><i>hello world</i></b>"
Я почти понимаю о декораторах и как он работает с одним из них в большинстве примеров.
В этом примере их 2. Из вывода кажется, что @make_italic
выполняется сначала, а затем @make_bold
.
Означает ли это, что для украшенных функций сначала будет запускаться функция, а затем двигаться к вершине для других декораторов? Как и @make_italic
сначала, а затем @make_bold
вместо противоположного.
Значит, это означает, что он отличается от нормы подхода сверху вниз в большинстве программных языков? Только для этого случая декоратора? Или я ошибаюсь?
Ответы
Ответ 1
Декораторы обертывают функцию, которую они украшают. Итак, make_bold
украсил результат декодера make_italic
, который украсил функцию hello
.
Синтаксис @decorator
- это действительно просто синтаксический сахар; следующее:
@decorator
def decorated_function():
# ...
действительно выполняется как:
def decorated_function():
# ...
decorated_function = decorator(decorated_function)
заменив исходный объект decorated_function
на все decorator()
.
Штабелирующие декораторы повторяют этот процесс наружу.
Итак, ваш образец:
@make_bold
@make_italic
def hello():
return "hello world"
можно расширить до:
def hello():
return "hello world"
hello = make_bold(make_italic(hello))
Когда вы вызываете hello()
сейчас, вы вызываете объект, возвращенный make_bold()
, действительно. make_bold()
возвращает a lambda
, который вызывает функцию make_bold
wrapped, которая является возвращаемым значением make_italic()
, которое также является лямбдой, которая вызывает исходный hello()
. Расширяя все эти вызовы, вы получаете:
hello() = lambda : "<b>" + fn() + "</b>" # where fn() ->
lambda : "<i>" + fn() + "</i>" # where fn() ->
return "hello world"
поэтому выход будет выглядеть следующим образом:
"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"
Ответ 2
Я использую Flask в качестве микро-фреймворка для производственного API, который я создаю. Я понимаю порядок декораторов методов и почему, но, как ни странно, мне пришлось изменить порядок (потому что это важно) моих декораторов из-за того, когда они выполняются. К моему удивлению, декораторы работали не в обычном порядке, а в обратном порядке. Другими словами, декораторы выполняются сверху вниз, спускаясь к оператору def
. Это продолжало сбивать меня с толку, потому что декораторы, которые я ожидал запустить первыми, внизу возле def
, фактически работали последними, и наоборот. Кто-нибудь видел это, и есть ли что-то в структуре Flask, что мешает с заказом? Я был бы удивлен, поскольку Flask, кажется, придерживается правил и духа Python, но мне странно, когда я вижу, что что-то фундаментальное работает не так, как ожидалось.