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()
Production: "<b><i>hello world</i></b>"
Je comprends à peu près les décorateurs et comment cela fonctionne avec l'un d'entre 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 d' @make_italic
abord alors @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? Rien que pour cette affaire de décorateur? Ou ai-je tort?
python
decorator
python-decorators
Débutant
la source
la source
a(b(x))
c'est du haut vers le bas (si vous imaginez cela divisé sur 3 lignes)Réponses:
Les décorateurs enveloppent la fonction qu'ils décorent. Donc
make_bold
décoré le résultat dumake_italic
décorateur, qui a décoré lahello
fonction.La
@decorator
syntaxe n'est en réalité que du sucre syntaxique; le suivant:est vraiment exécuté comme:
en remplaçant l'
decorated_function
objet d' origine par ce quidecorator()
est retourné.L'empilement des décorateurs répète ce processus vers l'extérieur .
Donc votre échantillon:
peut être étendu à:
Lorsque vous appelez
hello()
maintenant, vous appelez l'objet renvoyé parmake_bold()
, vraiment.make_bold()
a renvoyé unlambda
qui appelle la fonctionmake_bold
encapsulée, qui est la valeur de retour demake_italic()
, qui est également un lambda qui appelle l'originalhello()
. En développant tous ces appels, vous obtenez:donc la sortie devient:
la source
@make_bold #make_bold = make_bold(hello)
@make_italic #make_italic = make_italic (hello)
? Je ne suis pas sûr que sur cette base, il encapsulera le premier résultat. Ou pour ce cas de 2 wrappers, l'EDI utiliseramake_bold(make_italic(hello))
comme vous l'avez mentionné au lieu de ce que j'ai partagé?make_bold()
encapsule la sortie demake_italic()
, qui a été utilisé pour envelopperhello
, donc l'équivalent demake_bold(make_italic(hello))
.def inner: return "<b>" + fn() + "</b>"
, alorsreturn inner
serait la version de fonction «régulière»; pas si grande différence.make_italic
décorateur est exécuté avant lemake_bold
décorateur , car ilmake_italic
est le plus proche dudef
. Cependant, j'oublie l' ordre d'exécution du code décoré : lemake_bold
décoré (c'est-à-dire le lambda gras) est exécuté en premier, suivi du lambdamake_italic
décoré (c'est-à-dire le lambda en italique).