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()
Sortie: "<b><i>hello world</i></b>"
Je comprends à peu près les décorateurs et comment cela fonctionne avec l'un d'eux dans la plupart des exemples.
Dans cet exemple, il y en a 2. De la sortie, il semble que @make_italic
s'exécute d'abord, puis @make_bold
.
Cela signifie-t-il que pour les fonctions décorées, il exécutera d'abord la fonction puis se déplacera vers le haut pour les autres décorateurs? Comme @make_italic
d'abord, puis @make_bold
, au lieu du contraire.
Cela signifie donc qu'il est différent de la norme de l'approche descendante dans la plupart des langages de programmation? Juste pour ce cas de décorateur? Ou ai-je tort?
Décorateurs wrap la fonction qu'ils décorent. Ainsi make_bold
A décoré le résultat du décorateur make_italic
, Qui a décoré la fonction hello
.
La syntaxe @decorator
Est vraiment juste du sucre syntaxique; le suivant:
@decorator
def decorated_function():
# ...
est vraiment exécuté comme:
def decorated_function():
# ...
decorated_function = decorator(decorated_function)
remplacer l'objet decorated_function
d'origine par ce que decorator()
a renvoyé.
Empiler les décorateurs répète ce processus vers l'extérieur.
Donc votre échantillon:
@make_bold
@make_italic
def hello():
return "hello world"
peut être étendu à:
def hello():
return "hello world"
hello = make_bold(make_italic(hello))
Lorsque vous appelez hello()
maintenant, vous appelez vraiment l'objet renvoyé par make_bold()
. make_bold()
a renvoyé un lambda
qui appelle la fonction make_bold
encapsulée, qui est la valeur de retour de make_italic()
, qui est également un lambda qui appelle l'original hello()
. En élargissant tous ces appels, vous obtenez:
hello() = lambda : "<b>" + fn() + "</b>" # where fn() ->
lambda : "<i>" + fn() + "</i>" # where fn() ->
return "hello world"
donc la sortie devient:
"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"