2010-01-19 19 views
8

निम्नलिखित दो स्क्रिप्ट बराबर क्यों नहीं हैं?क्यों पाइथन सजावट परिभाषाओं में बंधे नहीं जा सकते हैं?

def makebold(fn): 
    def wrapped(): 
     return "<b>" + fn() + "</b>" 
    return wrapped 

def makeitalic(fn): 
    def wrapped(): 
     return "<i>" + fn() + "</i>" 
    return wrapped 

@makebold 
@makeitalic 
def hello(): 
    return "hello world" 

print hello() ## returns <b><i>hello world</i></b> 

और एक सजाया डेकोरेटर के साथ:

def makebold(fn): 
    def wrapped(): 
     return "<b>" + fn() + "</b>" 
    return wrapped 

@makebold 
def makeitalic(fn): 
    def wrapped(): 
     return "<i>" + fn() + "</i>" 
    return wrapped 

@makeitalic 
def hello(): 
    return "hello world" 

print hello() ## TypeError: wrapped() takes no arguments (1 given) 

मैं क्यों करना चाहते हैं पता करने के लिए:

(Understanding Python Decorators एक और सवाल से लिया)? मैंने MySQLdb अपवादों को पकड़ने के लिए retry सजावट लिखा है - यदि अपवाद क्षणिक है (उदा। टाइमआउट) यह थोड़ा सा सोने के बाद फ़ंक्शन को फिर से कॉल करेगा।

मुझे modifies_db सजावट भी मिली है जो कुछ कैश से संबंधित हाउसकीपिंग का ख्याल रखती है। modifies_dbretry से सजाया गया है, इसलिए मुझे लगता है कि modifies_db से सजाए गए सभी फ़ंक्शन भी पूरी तरह से पुनः प्रयास करेंगे। मुझसे कहां गलती हो गई?

+0

अच्छा सवाल। कुछ महीने पहले मैं अपने खुद के पुनः प्रयास करने वाले सजावट करने के दौरान उसी परिदृश्य में भाग गया था। यह एक पुनः प्रयास गिनती ले लिया, इसलिए समस्या ने खुद को थोड़ा अलग प्रस्तुत किया, लेकिन नीचे जैसा देखा गया वही समाधान था। –

उत्तर

9

दूसरे उदाहरण के साथ समस्या यह है कि

@makebold 
def makeitalic(fn): 
    def wrapped(): 
     return "<i>" + fn() + "</i>" 
    return wrapped 

makeitalic को सजाने के लिए कोशिश कर रही है, डेकोरेटर, और नहीं wrapped, यह समारोह लौटता है।

आप मैं क्या लगता है कि आप कुछ इस तरह से करना चाहते हैं कर सकते हैं:

def makeitalic(fn): 
    @makebold 
    def wrapped(): 
     return "<i>" + fn() + "</i>" 
    return wrapped 

यहाँ makeitalicmakebold का उपयोग करता wrapped को सजाने के लिए।

+2

+1 यह वास्तव में समस्या को इंगित करता है और इसके बजाय इसे कैसे किया जाना चाहिए। असल में समस्या सजावट करने वालों की सोच संरचना से होती है - लेकिन वे नहीं करते हैं। –

+0

यूप यह वही है जो मैं करने की कोशिश कर रहा था, और हां, मैंने सजाया कि सजावटी == कार्यात्मक संरचना – RobM

1

कारण यह है कि मेकबॉल्ड के अंदर लपेटा() किसी भी तर्क को स्वीकार नहीं करता है।

जब आप सजावट का उपयोग करते हैं तो इससे कुछ समस्याएं हो सकती हैं, मैं एक उदाहरण पोस्ट करूंगा कि आप जो चाहते हैं उसे हासिल करने के लिए, मुझे बस एक पल दें।

यहां आपको जो चाहिए वह एक कामकाजी उदाहरण है।

def makebold(rewrap=False): 
    if rewrap: 
     def inner(decorator): 
      def rewrapper(func): 
       def wrapped(*args, **kwargs): 
        return "<b>%s</b>" % decorator(func)(*args,**kwargs) 
       return wrapped 
      return rewrapper 
     return inner 

    else: 
     def inner(func): 
      def wrapped(*args, **kwargs): 
       return "<b>%s</b>" % func(*args, **kwargs)  
      return wrapped 
     return inner 

@makebold(rewrap=True) 
def makeitalic(fn): 
    def wrapped(*args, **kwargs): 
     return "<i>%s</i>" % fn(*args, **kwargs) 
    return wrapped 

@makeitalic 
def hello(): 
    return "hello world" 

@makebold() 
def hello2(): 
    return "Bob Dole"  

if __name__ == "__main__": 
    print hello() 
    print hello2() 

makebold थोड़े बदसूरत है, लेकिन यह कैसे एक डेकोरेटर कि वैकल्पिक रूप से एक और डेकोरेटर लपेट कर सकते हैं लिखने के लिए आपको दिखाता है।

<b><i>hello world</i></b> 
<b>Bob Dole</b> 

ध्यान दें कि makebold केवल पुनरावर्ती डेकोरेटर है:

यहाँ ऊपर स्क्रिप्ट से उत्पादन होता है। उपयोग में सूक्ष्म अंतर भी ध्यान दें: @makebold() बनाम @makeitalic

+0

-1 ... अत्यधिक जटिल, और "मेकटाइटलिक" बोल्ड + इटालिक के लिए एक बुरा नाम है।[यह उत्तर] देखें (http://stackoverflow.com/a/739665/850830) जो कोड की कुछ पंक्तियों में एक ही चीज़ करता है। – Ryan

0

समस्या "मेकटाइटलिक" ("एक तर्क लेती है) को" लपेटा "-फंक्शन" मेकबॉल्ड "में बदलकर शून्य तर्क लेती है।

उपयोग *args, **kwargs आगे श्रृंखला के नीचे तर्क पर पारित करने के लिए:

def wrapped(*args, **kwargs): 
    return "<b>" + fn(*args, **kwargs) + "</b>" 
+0

समस्या वास्तव में वास्तव में थोड़ा अधिक अलग है। एक और सजावट लपेटने के कुछ और मुद्दे हैं। –

संबंधित मुद्दे