Decorator execution order
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()
I roughly understand about decorators and how it works with one of it in most examples.
In this example, there are 2 of it. From the output, it seems that
@make_italic executes first, then
Does this mean that for decorated functions, it will first run the function first then moving towards to the top for other decorators? Like
@make_italic first then
@make_bold, instead of the opposite.
So this means that it is different from the norm of top-down approach in most programming lang? Just for this case of decorator? Or am I wrong?
Decorators wrap the function they are decorating. So
make_bold decorated the result of the
make_italic decorator, which decorated the
@decorator syntax is really just syntactic sugar; the following:
@decorator def decorated_function(): # ...
is really executed as:
def decorated_function(): # ... decorated_function = decorator(decorated_function)
replacing the original
decorated_function object with whatever
Stacking decorators repeats that process outward.
So your sample:
@make_bold @make_italic def hello(): return "hello world"
can be expanded to:
def hello(): return "hello world" hello = make_bold(make_italic(hello))
When you call
hello() now, you are calling the object returned by
make_bold() returned a
lambda that calls the function
make_bold wrapped, which is the return value of
make_italic(), which is also a lambda that calls the original
hello(). Expanding all these calls you get:
hello() = lambda : "<b>" + fn() + "</b>" # where fn() -> lambda : "<i>" + fn() + "</i>" # where fn() -> return "hello world"
so the output becomes:
"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"