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()
Wynik: "<b><i>hello world</i></b>"
Z grubsza rozumiem o dekoratorach i jak to działa z jednym z nich w większości przykładów.
W tym przykładzie jest ich 2. Z danych wyjściowych wynika, że @make_italic
najpierw jest wykonywany @make_bold
.
Czy to oznacza, że w przypadku funkcji dekoracyjnych najpierw uruchomi funkcję, a następnie przesunie się do góry dla innych dekoratorów? Tak jak @make_italic
wtedy @make_bold
, zamiast odwrotnie.
Czy to oznacza, że różni się od standardowego podejścia odgórnego w większości języków programowania? Tylko w tym przypadku dekoratora? A może się mylę?
python
decorator
python-decorators
Nowicjusz
źródło
źródło
a(b(x))
jest odgórny (jeśli wyobrażasz sobie, że jest podzielony na 3 wiersze)Odpowiedzi:
Dekoratorzy zawijają funkcję, którą dekorują. Tak
make_bold
ozdobiony efektemmake_italic
dekoratora, który zdobiłhello
funkcję.@decorator
Składnia jest naprawdę tylko cukier syntaktyczny; następujące:@decorator def decorated_function(): # ...
jest naprawdę wykonywany jako:
def decorated_function(): # ... decorated_function = decorator(decorated_function)
zastąpienie oryginalnego
decorated_function
przedmiotu tym, codecorator()
zwrócono.Układanie dekoratorów w stosy powtarza ten proces na zewnątrz .
Więc twoja próbka:
@make_bold @make_italic def hello(): return "hello world"
można rozszerzyć do:
def hello(): return "hello world" hello = make_bold(make_italic(hello))
Kiedy dzwonisz
hello()
teraz, tak naprawdę wywołujesz obiekt zwrócony przezmake_bold()
.make_bold()
zwrócił a,lambda
który wywołuje funkcjęmake_bold
opakowaną, która jest wartością zwracanąmake_italic()
, która jest również lambdą wywołującą oryginałhello()
. Rozszerzanie wszystkich otrzymywanych połączeń:hello() = lambda : "<b>" + fn() + "</b>" # where fn() -> lambda : "<i>" + fn() + "</i>" # where fn() -> return "hello world"
więc wynik wygląda następująco:
"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"
źródło
@make_bold #make_bold = make_bold(hello)
@make_italic #make_italic = make_italic (hello)
? Nie jestem pewien, czy opierając się na tym, zawinie pierwszy wynik. Czy w przypadku 2 opakowań IDE użyjemake_bold(make_italic(hello))
tego, o czym wspomniałeś, zamiast tego, co udostępniłem?make_bold()
zawija dane wyjściowemake_italic()
, które zostały użyte do zawijaniahello
, a więc odpowiednikmake_bold(make_italic(hello))
.def inner: return "<b>" + fn() + "</b>"
, toreturn inner
byłaby „zwykła” wersja funkcji; nie jest to duża różnica.make_italic
dekorator jest wykonywany przedmake_bold
dekoratorem , ponieważmake_italic
jest najbliżejdef
. Jednak zapominam, że dekorowana kolejność wykonania kodu:make_bold
dekorowana (tj. Pogrubiona lambda) jest wykonywana jako pierwsza, a następniemake_italic
dekorowana lambda (czyli lambda kursywa).