डेकोरेटर निष्पादन आदेश


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

आउटपुट: "<b><i>hello world</i></b>"

मैं सज्जाकारों के बारे में मोटे तौर पर समझता हूं और यह सबसे उदाहरणों में से एक के साथ कैसे काम करता है।

इस उदाहरण में, इसके 2 हैं। आउटपुट से, ऐसा लगता है कि @make_italicपहले निष्पादित होता है , फिर @make_bold

क्या इसका मतलब यह है कि सजाए गए कार्यों के लिए, यह पहले फ़ंक्शन को चलाएगा फिर अन्य सज्जाकारों के लिए शीर्ष की ओर बढ़ेगा? @make_italicपहले की तरह फिर @make_bold, इसके विपरीत।

तो इसका मतलब है कि यह सबसे प्रोग्रामिंग लैंग में टॉप-डाउन दृष्टिकोण के मानदंड से अलग है? सिर्फ डेकोरेटर के इस मामले के लिए? या मैं गलत हूँ?


4
हां यह नीचे से शुरू होकर अगले परिणाम तक जाता है
पादरी कनिंघम

1
@PadraicCunningham टिप्पणी उत्तर का एक महत्वपूर्ण हिस्सा है। एक संबंधित समस्या थी ( stackoverflow.com/questions/47042196/… )
shookees

मैं कहूंगा कि यह अभी भी टॉप-डाउन है, इस अर्थ में कि a(b(x))टॉप-डाउन है (यदि आप कल्पना करते हैं कि 3 रेखाओं में विभाजित है)
joel

जवाबों:


126

सज्जाकार उस फ़ंक्शन को लपेटते हैं जो वे सजा रहे हैं। इसलिए डेकोरेटर make_boldके परिणाम को make_italicसजाया, जिसने सजायाhello फ़ंक्शन को ।

@decoratorवाक्य रचना वास्तव में सिर्फ वाक्यात्मक चीनी है, निम्नलिखित:

@decorator
def decorated_function():
    # ...

वास्तव में के रूप में निष्पादित किया जाता है:

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

मूल decorated_functionवस्तु की जगह जो भी decorator()लौटे।

स्टैकिंग डेकोरेटर्स उस प्रक्रिया को बाहर की ओर दोहराते हैं ।

तो आपका नमूना:

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

इसका विस्तार किया जा सकता है:

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

जब आप hello()अभी कॉल करते हैं, तो आप make_bold()वास्तव में, द्वारा लौटाए गए ऑब्जेक्ट को कॉल कर रहे हैं । make_bold()एक lambdaहै make_boldजो लिपटे फ़ंक्शन को कॉल करता है, जो कि रिटर्न वैल्यू है make_italic(), जो कि एक लैम्ब्डा भी है जो मूल कॉल करता है hello()। आपको मिलने वाली इन सभी कॉल्स का विस्तार करना:

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

तो उत्पादन हो जाता है:

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

मै समझता हुँ। लेकिन इसका मतलब यह है कि जब इस मामले में 2 रैपर होते हैं, तो आईडीई स्वचालित रूप से पहले रैपर के परिणाम का पता लगाएगा और लपेट देगा? क्योंकि मैंने ऐसा सोचा था @make_bold #make_bold = make_bold(hello) @make_italic #make_italic = make_italic (hello)? मुझे यकीन नहीं है कि अगर इस पर आधारित है, तो यह पहला परिणाम लपेटेगा। या 2 रैपर के इस मामले के लिए, आईडीई का उपयोग करेगा make_bold(make_italic(hello))जैसा कि आपने मेरे द्वारा साझा किए गए के बजाय उल्लेख किया है?
नौसिखिया

3
@ नई: आपकी आईडीई यहां कुछ नहीं करती है; यह पायथन है जो रैपिंग करता है। मैंने आपको अपने अंतिम नमूने में दिखाया जो कि make_bold()आउटपुट को लपेटता है make_italic(), जिसे लपेटने के लिए इस्तेमाल किया गया था hello, इसलिए इसके बराबर make_bold(make_italic(hello))
मार्टिन पीटर्स

क्या आप लैम्बडा के उपयोग के बिना इस कोड का एक संस्करण प्रदान कर सकते हैं? मैंने कोशिश की थी। और इस उदाहरण में लैम्ब्डा का उपयोग क्यों किया जाता है? मैं लैम्ब्डा को समझने की कोशिश कर रहा हूं और इस उदाहरण में यह कैसे काम करता है लेकिन अभी भी समस्या है। मुझे लगता है कि लैम्ब्डा एक पंक्ति कार्यों की तरह है जिसे बहुत आसानी से पारित किया जा सकता है जैसे कि डीफ़ फ़ंक्शन के मानक की तुलना में?
नौसिखिया

def inner: return "<b>" + fn() + "</b>", तो return inner'नियमित' फ़ंक्शन संस्करण होगा; इतना बड़ा अंतर नहीं।
मार्टिन पीटर्स

मैं हमेशा ऑर्डर को लेकर उलझन में रहता हूं। "" डेकोरेटर्स को "डेफ" स्टेटमेंट के सबसे करीब से शुरू किया जाएगा, जिसे मैं "इन-आउट" कहता हूं। मुझे लगता है कि मार्टिज़न इसे "आउटवर्ड" कहता है। यह साधन make_italic डेकोरेटर से पहले मार डाला जाता है make_bold डेकोरेटर , क्योंकि make_italicके सबसे करीब है def। हालाँकि, मैं भूल गया कि सजाया गया कोड निष्पादन आदेश: make_bold सजाया (यानी बोल्ड लैम्ब्डा) पहले निष्पादित किया जाता है, उसके बाद make_italic सजाया लैम्ब्डा (यानी इटैलिक लैम्ब्डा)।
लाल मटर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.