Dekoratör yürütme emri


96
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()

Çıktı: "<b><i>hello world</i></b>"

Çoğu örnekte dekoratörleri ve bunlardan biriyle nasıl çalıştığını kabaca anlıyorum.

Bu örnekte 2 tane var. Çıktıdan, o @make_italiczaman önce çalıştırılıyor gibi görünüyor @make_bold.

Bu, dekore edilmiş işlevler için önce işlevi çalıştıracağı, ardından diğer dekoratörler için yukarı doğru hareket edeceği anlamına mı geliyor? Gibi @make_italicilk önce @make_boldyerine tam tersi.

Yani bu, çoğu programlama dilinde yukarıdan aşağıya yaklaşım normundan farklı olduğu anlamına mı geliyor? Sırf bu dekoratör davası için mi? Yoksa yanılıyor muyum?


4
evet, aşağıdan yukarıya sonucu bir sonrakine geçirerek başlar
Padraic Cunningham

1
@ PadraicCunningham yorumu da cevabın önemli bir kısmı. İlgili bir sorun vardı ( stackoverflow.com/questions/47042196/… )
2018

Hala yukarıdan aşağıya, yani yukarıdan aşağıya olduğunu söyleyebilirim a(b(x))(eğer bunu 3 çizgiye böldüğünü hayal ediyorsanız)
Joel

Yanıtlar:


131

Dekoratörler, süsledikleri işlevi sarar . Yani make_boldsonucunu dekore make_italicdekore dekoratör, helloişlevi.

@decoratorSözdizimi gerçekten sadece sözdizimsel şeker; devamındaki:

@decorator
def decorated_function():
    # ...

gerçekten şu şekilde yürütülür:

def decorated_function():
    # ...
decorated_function = decorator(decorated_function)

orijinal decorated_functionnesneyi decorator()geri dönen şeyle değiştirmek

İstifleme dekoratörleri bu süreci dışa doğru tekrarlar .

Öyleyse örneğiniz:

@make_bold
@make_italic
def hello():
  return "hello world"

şu şekilde genişletilebilir:

def hello():
  return "hello world"
hello = make_bold(make_italic(hello))

Aradığınızda hello()şimdi, tarafından döndürülen nesne aradığınız make_bold()gerçekten. make_bold()döndürülen lambdaişlevi çağıran bir döndürdü ; bu, aynı zamanda orijinali çağıran bir lambda olan make_bolddöndürülen değerdir . Aldığınız tüm bu aramaları genişletmek:make_italic()hello()

hello() = lambda : "<b>" + fn() + "</b>" #  where fn() ->
    lambda : "<i>" + fn() + "</i>" # where fn() -> 
        return "hello world"

böylece çıktı şu olur:

"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"

Anlıyorum. Ancak bu, bu durumda 2 sarmalayıcı olduğunda, IDE'nin ilk sarmalayıcının sonucunu otomatik olarak algılayıp saracağı anlamına mı geliyor? Bunu düşündüğüm için @make_bold #make_bold = make_bold(hello) @make_italic #make_italic = make_italic (hello)mi? Buna dayanıp dayanmayacağından emin değilim, ilk sonucu tamamlayacak. Veya bu 2 sarmalayıcı vakası için IDE, make_bold(make_italic(hello))paylaştığım şey yerine bahsettiğiniz gibi kullanacak mı?
Yeni Başlayan

3
@Newbie: IDE'niz burada hiçbir şey yapmaz; öyle Python sarma yapar. Size son make_bold()örneğimde göstermiştim çıktısını make_italic()sarmak için kullanılan hello, yani eşdeğeri make_bold(make_italic(hello)).
Martijn Pieters

Lambda kullanmadan bu kodun bir sürümünü sağlayabilir misiniz? .Format'ı denedim ama çalışmıyor. Ve bu örnekte neden lambda kullanılıyor? Lambda'yı ve bu örnekte nasıl çalıştığını anlamaya çalışıyorum ama hala problemler yaşıyorum. Lambda'nın, def fonksiyonlarının normuna kıyasla çok daha kolay geçirilebilen tek satırlık fonksiyonlar gibi olduğunu anladım.
Yeni Başlayan

def inner: return "<b>" + fn() + "</b>", return innerbu durumda 'normal' işlev sürümü olacaktır; o kadar büyük bir fark değil.
Martijn Pieters

Düzen konusunda hep kafam karışır. "... dekoratörler" def "deyimine en yakın" ben buna "içten dışa " diyorum. Sanırım Martijn buna "dışsal" diyor. Bu araçlar make_italic dekoratör önce yürütülür make_bold dekoratör , çünkü make_italicen yakın def. Ancak, dekore edilmiş kod yürütme sırasını unutuyorum : önce make_bold dekore edilmiş (yani kalın lambda), ardından make_italic dekore edilmiş lambda (yani italik lambda) çalıştırılır.
Kırmızı Bezelye
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.