def make_bold(fn):
return lambda : \"\" + fn() + \"\"
def make_italic(fn):
return lambda : \"\" + fn() + \"\"
@make_b
Decorators wrap the function they are decorating. So make_bold decorated the result of the make_italic decorator, which decorated the hello function.
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 decorator() returned.
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(), really. 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 : "" + fn() + "" # where fn() ->
lambda : "" + fn() + "" # where fn() ->
return "hello world"
so the output becomes:
"" + ("" + ("hello world") + "") + ""