2009-03-20 30 views
34

में मैं बरकरार निम्नलिखित सिद्धांतों के साथ सज्जाकार के रूप में उपयोग के लिए कक्षाओं का निर्माण करना चाहते हैं:डेकोरेटर कक्षाएं अजगर

  1. यह ऊपर से 1 समारोह पर कई ऐसे वर्ग सज्जाकार ढेर करने के लिए संभव होना चाहिए।
  2. परिणामी फ़ंक्शन नाम पॉइंटर को एक ही सजावट के बिना एक ही समारोह से अलग करने योग्य होना चाहिए, शायद यह किस प्रकार/वर्ग के लिए बचा सकता है।
  3. सजावट करने वालों को आदेश देना प्रासंगिक नहीं होना चाहिए जब तक वास्तव में सजावटकर्ताओं द्वारा अनिवार्य नहीं किया जाता है। अर्थात। स्वतंत्र सजावट किसी भी क्रम में लागू किया जा सकता है।

यह एक Django परियोजना के लिए है, और विशेष मामले मैं पर काम कर रहा हूँ अब विधि 2 सज्जाकार की जरूरत है, और एक सामान्य अजगर समारोह के रूप में प्रकट करने के लिए:

@AccessCheck 
@AutoTemplate 
def view(request, item_id) {} 

@AutoTemplate समारोह बदल कर कि एक HttpResponse लौटने की बजाय, यह संदर्भ में उपयोग के लिए एक शब्दकोश देता है। एक अनुरोध कॉन्टेक्स्ट का उपयोग किया जाता है, और टेम्पलेट का नाम विधि नाम और मॉड्यूल से अनुमानित है।

@AccessCheck item_id के आधार पर उपयोगकर्ता पर अतिरिक्त चेक जोड़ता है।

मुझे लगता है कि यह केवल कन्स्ट्रक्टर को सही करने और उचित विशेषताओं की प्रतिलिपि बनाने के लिए अनुमान लगा रहा है, लेकिन ये कौन सा गुण हैं?

के रूप में मैं का वर्णन निम्नलिखित डेकोरेटर काम नहीं करेगा:

class NullDecl (object): 
    def __init__ (self, func): 
     self.func = func 
    def __call__ (self, * args): 
     return self.func (*args) 

निम्नलिखित कोड द्वारा प्रदर्शन के रूप में:

@NullDecl 
@NullDecl 
def decorated(): 
    pass 

def pure(): 
    pass 

# results in set(['func_closure', 'func_dict', '__get__', 'func_name', 
# 'func_defaults', '__name__', 'func_code', 'func_doc', 'func_globals']) 
print set(dir(pure)) - set(dir(decorated)); 

साथ ही, कोशिश करते हैं और जोड़ने "प्रिंट समारोह नाम।" में नलडेक्ल कंस्ट्रक्टर, और यह पहले सजावट के लिए काम करेगा, लेकिन दूसरा नहीं - जैसा कि नाम गायब होगा।

रिफाइंड eduffy के एक बिट का जवाब है, और यह बहुत अच्छी तरह से काम करने के लिए लगता है: तो

class NullDecl (object): 
    def __init__ (self, func): 
     self.func = func 
     for name in set(dir(func)) - set(dir(self)): 
     setattr(self, name, getattr(func, name)) 

    def __call__ (self, *args): 
     return self.func (*args) 

और तुम:

class NullDecl (object): 
    def __init__ (self, func): 
     self.func = func 
     for n in set(dir(func)) - set(dir(self)): 
      setattr(self, n, getattr(func, n)) 

    def __call__ (self, * args): 
     return self.func (*args) 
    def __repr__(self): 
     return self.func 
+1

+1 क्योंकि मैं मुझे यकीन नहीं है कि किसी ने इस सवाल को क्यों वोट दिया। यह एक अच्छा सवाल है: एसओ पर अधिकांश सजावटी प्रश्न कक्षाओं को सजावटी के रूप में उपयोग नहीं करते हैं। जो कुछ भी सोच सकता है वह किसी फ़ंक्शन की बजाय कक्षा का उपयोग करता है, यह एक वैध प्रश्न है और उपयोग के मामले में पूरी तरह उपयुक्त हो सकता है। –

उत्तर

21

एक do-कुछ भी नहीं डेकोरेटर वर्ग इस प्रकार दिखाई देगा यह आम तौर पर लागू कर सकते हैं:

@NullDecl 
def myFunc (x,y,z): 
    return (x+y)/z 
+0

मेरी टिप्पणी देखें कि आपका कोड क्यों काम नहीं करेगा जैसा मैंने कहा था। – Staale

+0

मैंने अपना खुद का फ़िक्स जोड़ा ताकि यह ठीक से काम करे। मदद के लिए धन्यवाद, आमतौर पर बहुत बुनियादी शुरू करने में मदद करता है। – Staale

+6

शायद परिभाषा 'def __call__ (self, * args) में' ** kwargs' जोड़ने के लिए एक जगह भी है: '(और बाद में' self.func 'के आमंत्रण के लिए)? –

10

decorator module मदद क्या आप हस्ताक्षर-संरक्षित सजावटी लिख रहे हैं।

और PythonDecoratorLibrary सजावटी के लिए उपयोगी उदाहरण प्रदान कर सकता है।

7

एक सजावट बनाने के लिए जो किसी ऐसे मामले में कार्य को लपेटता है जो उन्हें मूल कार्य से अलग करने योग्य बनाता है, functools.wraps का उपयोग करें।

उदाहरण:


def mydecorator(func): 
    @functools.wraps(func): 
    def _mydecorator(*args, **kwargs): 
     do_something() 
     try: 
      return func(*args, **kwargs) 
     finally: 
      clean_up() 
    return _mydecorator 

# ... and with parameters 
def mydecorator(param1, param2): 
    def _mydecorator(func): 
     @functools.wraps(func) 
     def __mydecorator(*args, **kwargs): 
      do_something(param1, param2) 
      try: 
       return func(*args, **kwargs) 
      finally: 
       clean_up() 
     return __mydecorator 
    return _mydecorator 

(मेरी निजी पसंद फ़ंक्शन का उपयोग करके सज्जाकार बनाने के लिए है नहीं वर्ग) है

सज्जाकार के आदेश इस प्रकार है:


@d1 
@d2 
def func(): 
    pass 

# is equivalent to 
def func(): 
    pass 

func = d1(d2(func)) 
+0

मैं कक्षाओं का उपयोग करना पसंद करता हूं, लेकिन मुझे लगता है कि यह मेरी जावा पृष्ठभूमि के कारण है। मुझे लगता है कि मैंने किसी को सजावटी के लिए कक्षाओं का उपयोग करने की सिफारिश की है, लेकिन मुझे लगता है कि बुरी सलाह थी। – Staale

+2

यदि आप कक्षाओं का उपयोग करना चाहते हैं, तो मुझे यकीन नहीं है कि आपने @ functools.wraps कहां रखा है। मुझे काम लगता है क्योंकि सजावटी अधिक पाइथनिक हैं। और कोड छोटा है। – codeape

+0

अपने पैरामीटर उदाहरण में, "func" कहां से आता है? यह mydecorator() के लिए पैरामीटर की सूची में नहीं है ... –

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