2011-10-09 18 views
10

में तर्कों पर काम करते हैं, मैं एक फ़ंक्शन सजावट लिख रहा हूं जो फ़ंक्शन के पहले तर्क में रूपांतरण लागू करेगा। यह ठीक काम करता है अगर मैं केवल एक बार अपने कार्यों को सजाने के लिए, लेकिन अगर मैं उन्हें दो बार सजाता हूं तो मुझे एक त्रुटि मिलती है। नीचे कुछ कोड है जो समस्या का प्रदर्शन करता है, यह उस कोड का सरलीकृत संस्करण है जिस पर मैं काम कर रहा हूं। मैं कोड इतनी के रूप में समस्यानेस्टेड फ़ंक्शन सजावट जो पायथन

from inspect import getargspec 
from functools import wraps 

def dec(id): 
    def _dec(fn): 
     @wraps(fn) 
     def __dec(*args, **kwargs): 
      if len(args): 
       return fn(args[0], *args[1:], **kwargs) 
      else: 
       first_arg = getargspec(fn).args[0] 
       new_kwargs = kwargs.copy() 
       del new_kwargs[first_arg] 
       return fn(kwargs[first_arg], **new_kwargs) 
     return __dec 
    return _dec 

@dec(1) 
def functionWithOneDecorator(a, b, c): 
    print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c) 

@dec(1) 
@dec(2) 
def functionWithTwoDecorators(a, b, c): 
    print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c) 

functionWithOneDecorator(1, 2, 3) 
functionWithOneDecorator(1, b=2, c=3) 
functionWithOneDecorator(a=1, b=2, c=3) 
functionWithOneDecorator(c=3, b=2, a=1) 

functionWithTwoDecorators(1, 2, 3) 
functionWithTwoDecorators(1, b=2, c=3) 
functionWithTwoDecorators(a=1, b=2, c=3) 
functionWithTwoDecorators(c=3, b=2, a=1) 

से विचलित नहीं करने के लिए जब मैं ऊपर कोड मैं निम्नलिखित आउटपुट प्राप्त चलने वाले रूपांतरण करता है बाहर रखा गया है

functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithOneDecorator(a = 1, b = 2, c = 3) 
functionWithTwoDecorators(a = 1, b = 2, c = 3) 
functionWithTwoDecorators(a = 1, b = 2, c = 3) 
IndexError: list index out of range 

इसका कारण यह है जब दूसरी डेकोरेटर तर्क नामों को खोजने के लिए सजाए गए फ़ंक्शन का निरीक्षण करता है और विफल रहता है क्योंकि यह एक सजावट को सजा रहा है और केवल * तर्क और ** kwargs लेता है।

मैं समस्या के आस-पास के तरीकों के बारे में सोच सकता हूं जो ऊपर दिए गए कोड में काम करेंगे, लेकिन अगर मेरे समारोह में एक सजावट और तीसरे पक्ष से एक समारोह को सजाया गया तो भी टूट जाएगा। क्या इसे ठीक करने का कोई सामान्य तरीका है? या क्या एक ही परिणाम प्राप्त करने का एक बेहतर तरीका है?

अद्यतन:decorator module को इंगित करने के लिए @ हर्नन के लिए धन्यवाद। यह वास्तव में इस समस्या को हल करता है। अब मेरी कोड इस तरह दिखता है:

from decorator import decorator 

def dec(id): 
    @decorator 
    def _dec(fn, *args, **kwargs): 
     return fn(args[0], *args[1:], **kwargs) 
    return _dec 

@dec(1) 
def functionWithOneDecorator(a, b, c): 
    print "functionWithOneDecorator(a = %s, b = %s, c = %s)" % (a, b, c) 

@dec(1) 
@dec(2) 
def functionWithTwoDecorators(a, b, c): 
    print "functionWithTwoDecorators(a = %s, b = %s, c = %s)" % (a, b, c) 

functionWithOneDecorator(1, 2, 3) 
functionWithOneDecorator(1, b=2, c=3) 
functionWithOneDecorator(a=1, b=2, c=3) 
functionWithOneDecorator(c=3, b=2, a=1) 

functionWithTwoDecorators(1, 2, 3) 
functionWithTwoDecorators(1, b=2, c=3) 
functionWithTwoDecorators(a=1, b=2, c=3) 
functionWithTwoDecorators(c=3, b=2, a=1)  

बहुत क्लीनर, और यह काम करता है!

+1

क्यों तर्क [0], * तर्क [1:] ', यह' * args' जैसा ही है? –

+0

इस सजावट के साथ आप हल करने की कोशिश कर रहे हैं? जहां तक ​​मैं कह सकता हूं कि इसका मुख्य लक्ष्य यह सुनिश्चित करना है कि पहला दिया गया तर्क - कीवर्ड/वैकल्पिक या अन्यथा - लिपटे फ़ंक्शन पर हमेशा से गुजरता है क्योंकि यह "पहला" तर्क है। इसके अलावा, सजावटी को 'आईडी' तर्क का इरादा महत्व क्या है? यह कहीं भी इस्तेमाल नहीं किया जाता है। –

+0

मैं पहले तर्क में रूपांतरण लागू करना चाहता हूं। ऊपर दिए गए कोड में मैंने कोड को बहिष्कृत किया है जो रूपांतरण करता है ताकि समस्या से विचलित न हो। –

उत्तर

5

समस्या यह है कि आपके सजाए गए फ़ंक्शन का हस्ताक्षर मूल से हस्ताक्षर (getargspec) नहीं है। यह decorator module की मदद से वास्तव में अच्छी तरह से समझाया गया है जिसे आप अपनी समस्या का समाधान कर सकते हैं। असल में, आपको एक हस्ताक्षर-संरक्षित सजावटी का उपयोग करना चाहिए, ताकि दूसरा सजावटी पहले के समान हस्ताक्षर देख सके।

+0

शानदार, यह वही है जो मैं ढूंढ रहा था। –

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