2012-05-25 6 views
7

में सजावटी पुनरावर्ती कार्य मुझे समझने में कठिनाई हो रही है कि एक सजाया गया रिकर्सिव फ़ंक्शन कैसे काम करता है। निम्नलिखित स्निपेट के लिए:पाइथन

def dec(f): 
    def wrapper(*argv): 
     print(argv, 'Decorated!') 
     return(f(*argv)) 
    return(wrapper) 

def f(n): 
    print(n, 'Original!') 
    if n == 1: return(1) 
    else: return(f(n - 1) + n) 

print(f(5)) 
print 

dec_f = dec(f) 
print(dec_f(5)) 
print 

f = dec(f) 
print(f(5)) 

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

(5, 'Original!') 
(4, 'Original!') 
(3, 'Original!') 
(2, 'Original!') 
(1, 'Original!') 
15 

((5,), 'Decorated!') 
(5, 'Original!') 
(4, 'Original!') 
(3, 'Original!') 
(2, 'Original!') 
(1, 'Original!') 
15 

((5,), 'Decorated!') 
(5, 'Original!') 
((4,), 'Decorated!') 
(4, 'Original!') 
((3,), 'Decorated!') 
(3, 'Original!') 
((2,), 'Decorated!') 
(2, 'Original!') 
((1,), 'Decorated!') 
(1, 'Original!') 
15 

पहले एक प्रिंट च (एन) इसलिए स्वाभाविक रूप से यह प्रिंट 'मूल' हर बार च (एन) रिकर्सिवली कहा जाता है।

दूसरा प्रिंट def_f (n) प्रिंट करता है, इसलिए जब एन को रैपर में पास किया जाता है तो यह f (n) को पुनरावर्ती रूप से कॉल करता है। लेकिन रैपर स्वयं रिकर्सिव नहीं है इसलिए केवल एक 'सजाया' मुद्रित किया जाता है।

तीसरा एक पहेली मुझे, जो सजावटी @ डीईसी का उपयोग करने जैसा ही है। सजाए गए एफ (एन) रैपर को पांच बार क्यों कहते हैं? मुझे लगता है कि def_f = dec (f) और f = dec (f) केवल दो कीवर्ड दो समान फ़ंक्शन ऑब्जेक्ट्स से बंधे हैं। क्या कुछ और चल रहा है जब सजाए गए फ़ंक्शन को अनावृत के समान नाम दिया जाता है?

धन्यवाद!

+1

मूल 'f' समारोह के संदर्भ में अभी भी मौजूद है अंदर आवरण अंदर func.__name__ और f.__name__ मुद्रण, इस प्रकार है कि एक कहा जाता है से देख सकते हैं। जब आप 'f = dec (f)' करते हैं, तो आप हमेशा नया फ़ंक्शन कॉल करेंगे। और नया फ़ंक्शन मूल को कॉल करेगा। – JBernardo

+0

'सजावटी 'यहां उपयोग करने का सही शब्द नहीं हो सकता है, क्योंकि आप वास्तव में फ़ंक्शन में सजावट लागू नहीं करते हैं। 'F = dec (f)' का आपका अंतिम परीक्षण लगभग (अगर नहीं है) '@dec def f' –

उत्तर

4

जैसा कि आपने कहा था, पहले को सामान्य के रूप में जाना जाता है।

दूसरा व्यक्ति वैश्विक दायरे में dec_f नामक f के सजाए गए संस्करण को रखता है। Dec_f को बुलाया जाता है, ताकि प्रिंट "सजाने वाले" हो जाएं, लेकिन एफ फ़ंक्शन के अंदर dec को पास किया गया है, तो आप f को कॉल करें, dec_f नहीं। नाम एफ को देखा गया है और वैश्विक दायरे में पाया गया है, जहां इसे अभी भी रैपर के बिना परिभाषित किया गया है, इसलिए से, केवल एफ को बुलाया जाता है।

3re उदाहरण में, आप सजाए गए संस्करण को नाम f में असाइन करते हैं, इसलिए जब फ़ंक्शन f के अंदर, नाम f देखा जाता है, यह वैश्विक दायरे में दिखता है, f पाता है, जो अब सजाया गया संस्करण है।

+0

जैसा ही है! यह वही है जिसे मैं देख रहा था। तो समस्या def f (f (n-1) + n) def f में f स्टेट है, जहां f (n-1) अब नया dec (f) है। – jianglai

5

पायथन में सभी असाइनमेंट केवल वस्तुओं के लिए बाध्यकारी नाम हैं। जब आप

f = dec(f) 

है तुम क्या कर रहे dec(f) के रिटर्न मान पर नाम f बाध्यकारी है। उस बिंदु पर, f अब मूल कार्य को संदर्भित नहीं करता है। मूल कार्य अभी भी मौजूद है और इसे नए f द्वारा बुलाया जाता है, लेकिन आपके पास अब नाम मूल फ़ंक्शन के संदर्भ में नहीं है।

1

आपका फ़ंक्शन f नामक किसी चीज़ को आमंत्रित करता है, जो कि पाइथन संलग्न क्षेत्र में दिखता है।

बयान f = dec(f), f अभी भी अनचाहे फ़ंक्शन से बंधे हैं, इसलिए यही कहा जा रहा है।

0

सज्जाकार से संकेत मिलता है एक प्रस्तावना/उपसंहार से पहले या किसी अन्य समारोह के बाद एक किया जाना है, हम इसे कई बार पुनरावर्ती कार्यों के साथ अनुकरण सज्जाकार कर बच सकते हैं।

उदाहरण के लिए:

def timing(f): 
    def wrapper(*args): 
     t1 = time.clock(); 
     r = apply(f,args) 
     t2 = time.clock(); 
     print"%f seconds" % (t2-t1) 
     return r 
    return wrapper 

@timing 
def fibonacci(n): 
    if n==1 or n==2: 
     return 1 
    return fibonacci(n-1)+fibonacci(n-2) 

r = fibonacci(5) 
print "Fibonacci of %d is %d" % (5,r) 

का उत्पादन:

r = timing(fibonacci)(5) 
print "Fibonacci %d of is %d" % (5,r) 

कौन सा पैदा करता है: के रूप में

0.000000 seconds 
0.000001 seconds 
0.000026 seconds 
0.000001 seconds 
0.000030 seconds 
0.000000 seconds 
0.000001 seconds 
0.000007 seconds 
0.000045 seconds 
Fibonacci of 5 is 5 

हम डेकोरेटर अनुकरण कर सकते हैं केवल एक प्रस्तावना/उपसंहार के लिए मजबूर करने

0.000010 seconds 
Fibonacci 5 of is 5 
0

अपने कोड थोड़ा

def dec(func): 
    def wrapper(*argv): 
     print(argv, 'Decorated!') 
     return(func(*argv)) 
    return(wrapper) 

def f(n): 
    print(n, 'Original!') 
    if n == 1: return(1) 
    else: return(f(n - 1) + n) 

print(f(5)) 
print 

dec_f = dec(f) 
print(dec_f(5)) 
print 

f = dec(f) 
print(f(5)) 

बदल दिया मुझे लगता है कि यह बातें यहाँ और अधिक स्पष्ट सा होगा, आवरण समारोह वास्तव में गुंजाइश enclosing से समारोह वस्तु बंद कर देता है। तो रैपर के अंदर फंक करने के लिए हर कॉल मूल एफ को कॉल करेगा लेकिन एफ के भीतर रिकर्सिव कॉल एफ के सजाए गए संस्करण को कॉल करेगा।

आप वास्तव में बस समारोह f