2009-08-11 7 views
89

एक लिख सकते हैं sth की तरह:अजगर सज्जाकार

class Test(object): 
    def _decorator(self, foo): 
     foo() 

    @self._decorator 
    def bar(self): 
     pass 

यह विफल रहता है: @self में आत्म अज्ञात है

मैं भी करने की कोशिश की:

@Test._decorator(self) 

जो भी विफल रहता है: टेस्ट अज्ञात

यदि अस्थायी करना चाहते हैं। से पहले उन्हें बदलने के पहले सजावट में कुछ उदाहरण चर बदलें और सजाए गए विधि को चलाएं।

धन्यवाद।

उत्तर

52

जो आप करना चाहते हैं वह संभव नहीं है। उदाहरण के लिए, या नहीं, नीचे दिए गए कोड मान्य दिखता है:

class Test(object): 

    def _decorator(self, foo): 
     foo() 

    def bar(self): 
     pass 
    bar = self._decorator(bar) 

यह जाहिर है, नहीं मान्य के बाद से self उस बिंदु पर परिभाषित नहीं है। यह Test के लिए जाता है क्योंकि इसे तब तक परिभाषित नहीं किया जाएगा जब तक कक्षा स्वयं परिभाषित न हो (जो इसकी प्रक्रिया में है)। मैं आपको यह कोड स्निपेट दिखा रहा हूं क्योंकि यह है कि आपका सजावटी स्निपेट बदल जाता है।

तो, जैसा कि आप देख सकते हैं, इस तरह के एक सजावटी में उदाहरण का उपयोग करना वास्तव में संभव नहीं है क्योंकि सजावटकर्ताओं को जो भी कार्य/विधि से जुड़ा हुआ है, उसकी परिभाषा के दौरान लागू किया जाता है और नहीं।

आप वर्ग स्तर तक पहुँच की जरूरत है, इस प्रयास करें:

class Test(object): 

    @classmethod 
    def _decorator(cls, foo): 
     foo() 

    def bar(self): 
     pass 
Test.bar = Test._decorator(Test.bar) 
+6

"असंभव" तथ्यात्मक रूप से गलत है। – zneak

+3

को आपके उत्तर के लिए – natb1

168

चाहेंगे कुछ इस तरह है कि तुम क्या जरूरत है?

class Test(object): 
    def _decorator(foo): 
     def magic(self) : 
      print "start magic" 
      foo(self) 
      print "end magic" 
     return magic 

    @_decorator 
    def bar(self) : 
     print "normal call" 

test = Test() 

test.bar() 

यह डेकोरेटर का उपयोग करने की आत्म करने के लिए कॉल से बचा जाता है और यह एक नियमित रूप से विधि के रूप में वर्ग नाम स्थान में छिपा छोड़ देता है।

>>> import stackoverflow 
>>> test = stackoverflow.Test() 
>>> test.bar() 
start magic 
normal call 
end magic 
>>> 

टिप्पणी में सवाल का जवाब देने संपादित:

अन्य वर्ग

class Test(object): 
    def _decorator(foo): 
     def magic(self) : 
      print "start magic" 
      foo(self) 
      print "end magic" 
     return magic 

    @_decorator 
    def bar(self) : 
     print "normal call" 

    _decorator = staticmethod(_decorator) 

class TestB(Test): 
    @Test._decorator 
    def bar(self): 
     print "override bar in" 
     super(TestB, self).bar() 
     print "override bar out" 

print "Normal:" 
test = Test() 
test.bar() 
print 

print "Inherited:" 
b = TestB() 
b.bar() 
print 
+0

के नीचे अधिक सटीक उत्तर संदर्भित करने के लिए शायद अपडेट किया जाना चाहिए। हां यह काम करेगा अगर यह इस तथ्य के लिए नहीं था कि मैं चाहता था कि सजावटी आवृत्ति चर पर कुछ ओप करने के लिए - और इसके लिए स्वयं की आवश्यकता होगी। – hcvst

+4

सजावट या सजाया समारोह? लौटाए गए "जादू" फ़ंक्शन पर ध्यान दें कि जब बार "बार" को एक उदाहरण पर बुलाया जाता है तो ऊपर एक स्व चर प्राप्त होता है और वह पहले और बाद में (या यहां तक ​​कि नहीं) के आवृत्ति चर के लिए कुछ भी कर सकता है जिसे इसे "बार" कहा जाता है । कक्षा घोषित करते समय इंस्टेंस चर के रूप में ऐसी कोई चीज़ नहीं है। क्या आप सजावट के भीतर से कक्षा में कुछ करना चाहते थे? मुझे नहीं लगता कि यह एक मूर्खतापूर्ण उपयोग है। –

+0

धन्यवाद माइकल, केवल अब देखा कि यह वही है जो मैं चाहता था। – hcvst

2

में छिपा डेकोरेटर का उपयोग कैसे करें एक बहुत ही इसी तरह की समस्या पर शोध करते हुए मैं इस सवाल पाया। मेरा समाधान समस्या को दो हिस्सों में विभाजित करना है। सबसे पहले, आपको उस डेटा को कैप्चर करने की आवश्यकता है जिसे आप कक्षा विधियों से जोड़ना चाहते हैं। इस मामले में, हैंडलर_for उस कमांड के आउटपुट के लिए एक यूनिक्स कमांड को हैंडलर से संबद्ध करेगा।

class OutputAnalysis(object): 
    "analyze the output of diagnostic commands" 
    def handler_for(name): 
     "decorator to associate a function with a command" 
     def wrapper(func): 
      func.handler_for = name 
      return func 
     return wrapper 
    # associate mount_p with 'mount_-p.txt' 
    @handler_for('mount -p') 
    def mount_p(self, slurped): 
     pass 

अब हमने प्रत्येक कक्षा विधि के साथ कुछ डेटा जोड़ा है, हमें उस डेटा को इकट्ठा करने और कक्षा विशेषता में संग्रहीत करने की आवश्यकता है।

OutputAnalysis.cmd_handler = {} 
for value in OutputAnalysis.__dict__.itervalues(): 
    try: 
     OutputAnalysis.cmd_handler[value.handler_for] = value 
    except AttributeError: 
     pass 
4

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

class myclass(object): 
    def __init__(self): 
     self.property = "HELLO" 

    @adecorator(property="GOODBYE") 
    def method(self): 
     print self.property 

यहाँ डेकोरेटर कोड है

class adecorator (object): 
    def __init__ (self, *args, **kwargs): 
     # store arguments passed to the decorator 
     self.args = args 
     self.kwargs = kwargs 

    def __call__(self, func): 
     def newf(*args, **kwargs): 

      #the 'self' for a method function is passed as args[0] 
      slf = args[0] 

      # replace and store the attributes 
      saved = {} 
      for k,v in self.kwargs.items(): 
       if hasattr(slf, k): 
        saved[k] = getattr(slf,k) 
        setattr(slf, k, v) 

      # call the method 
      ret = func(*args, **kwargs) 

      #put things back 
      for k,v in saved.items(): 
       setattr(slf, k, v) 

      return ret 
     newf.__doc__ = func.__doc__ 
     return newf 

नोट: क्योंकि मैं एक वर्ग डेकोरेटर का उपयोग किया है आप, यहां तक ​​कि कोष्ठक साथ @adecorator() उपयोग करने के लिए कार्यों को सजाने के लिए पर की आवश्यकता होगी यदि आप सजावटी वर्ग कन्स्ट्रक्टर को कोई तर्क नहीं देते हैं।

1

डेकोरेटर बेहतर एक वस्तु विधि की कार्यक्षमता बनाम एक संपूर्ण वस्तु (समारोह वस्तुओं सहित) की कार्यक्षमता जो सामान्य उदाहरण विशेषताओं पर निर्भर करेगा संशोधित करने के लिए उपयुक्त लगते। उदाहरण के लिए:

def mod_bar(cls): 
    # returns modified class 

    def decorate(fcn): 
     # returns decorated function 

     def new_fcn(self): 
      print self.start_str 
      print fcn(self) 
      print self.end_str 

     return new_fcn 

    cls.bar = decorate(cls.bar) 
    return cls 

@mod_bar 
class Test(object): 
    def __init__(self): 
     self.start_str = "starting dec" 
     self.end_str = "ending dec" 

    def bar(self): 
     return "bar" 

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

>>> import Test 
>>> a = Test() 
>>> a.bar() 
starting dec 
bar 
ending dec 
0

आप डेकोरेटर को सजाने कर सकते हैं:

import decorator 

class Test(object): 
    @decorator.decorator 
    def _decorator(foo, self): 
     foo(self) 

    @_decorator 
    def bar(self): 
     pass 
2

इस से self तक पहुँचने के लिए एक तरह से मैं के बारे में पता है (और इस्तेमाल किया है) है एक ही कक्षा के अंदर परिभाषित एक सजावट के अंदर:

class Thing(object): 
    def __init__(self, name): 
     self.name = name 

    def debug_name(function): 
     def debug_wrapper(*args): 
      self = args[0] 
      print 'self.name = ' + self.name 
      print 'running function {}()'.format(function.__name__) 
      function(*args) 
      print 'self.name = ' + self.name 
     return debug_wrapper 

    @debug_name 
    def set_name(self, new_name): 
     self.name = new_name 

आउटपुट (अजगर 2.7.10 पर परीक्षण):

>>> a = Thing('A') 
>>> a.name 
'A' 
>>> a.set_name('B') 
self.name = A 
running function set_name() 
self.name = B 
>>> a.name 
'B' 

उपरोक्त उदाहरण मूर्खतापूर्ण है, लेकिन पता चलता है कि यह काम करता है।

एक उदाहरण विधि डेकोरेटर जो तर्क लेता है और तर्क के साथ एक समारोह और एक वापसी मान पर कार्य करता है:

3
class Example(object): 

    def wrapper(func): 
     @functools.wraps(func) 
     def wrap(self, *args, **kwargs): 
      print "inside wrap" 
      return func(self, *args, **kwargs) 
     return wrap 

    @wrapper 
    def method(self): 
     pass 

    wrapper = staticmethod(wrapper) 
1

यहाँ यह आगे कुछ कदम उठाने के लिए माइकल स्पीयर के जवाब पर एक विस्तार है।

class Test(object): 
    "Prints if x == y. Throws an error otherwise." 
    def __init__(self, x): 
     self.x = x 

    def _outer_decorator(y): 
     def _decorator(foo): 
      def magic(self, *args, **kwargs) : 
       print("start magic") 
       if self.x == y: 
        return foo(self, *args, **kwargs) 
       else: 
        raise ValueError("x ({}) != y ({})".format(self.x, y)) 
       print("end magic") 
      return magic 

     return _decorator 

    @_outer_decorator(y=3) 
    def bar(self, *args, **kwargs) : 
     print("normal call") 
     print("args: {}".format(args)) 
     print("kwargs: {}".format(kwargs)) 

     return 27 

और फिर

In [2]: 

    test = Test(3) 
    test.bar(
     13, 
     'Test', 
     q=9, 
     lollipop=[1,2,3] 
    ) 
    ​ 
    start magic 
    normal call 
    args: (13, 'Test') 
    kwargs: {'q': 9, 'lollipop': [1, 2, 3]} 
Out[2]: 
    27 
In [3]: 

    test = Test(4) 
    test.bar(
     13, 
     'Test', 
     q=9, 
     lollipop=[1,2,3] 
    ) 
    ​ 
    start magic 
    --------------------------------------------------------------------------- 
    ValueError        Traceback (most recent call last) 
    <ipython-input-3-576146b3d37e> in <module>() 
      4  'Test', 
      5  q=9, 
    ----> 6  lollipop=[1,2,3] 
      7) 

    <ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs) 
     11      return foo(self, *args, **kwargs) 
     12     else: 
    ---> 13      raise ValueError("x ({}) != y ({})".format(self.x, y)) 
     14     print("end magic") 
     15    return magic 

    ValueError: x (4) != y (3)