2010-07-13 5 views
7

मैं एक सजावट बनाना चाहता हूं जो संपत्ति की तरह काम करता है, केवल यह केवल सजाए गए फ़ंक्शन को केवल एक बार कॉल करता है, और बाद में कॉल हमेशा पहली कॉल का परिणाम वापस कर देता है। एक उदाहरण:किसी संपत्ति के आलसी प्रारंभिकरण के लिए सजावट बनाने के लिए

def SomeClass(object): 
    @LazilyInitializedProperty 
    def foo(self): 
     print "Now initializing" 
     return 5 

>>> x = SomeClass() 
>>> x.foo 
Now initializing 
5 
>>> x.foo 
5 

मेरा विचार इस के लिए एक कस्टम सजावट लिखना था। तो मैं शुरू कर दिया है, और इस कितनी दूर मैं आया है:

class LazilyInitializedProperty(object): 
    def __init__(self, function): 
     self._function = function 

    def __set__(self, obj, value): 
     raise AttributeError("This property is read-only") 

    def __get__(self, obj, type): 
     # problem: where to store the value once we have calculated it? 

आप देख सकते हैं, मैं जहां कैश की गई मूल्य स्टोर करने के लिए पता नहीं है। सबसे सरल समाधान केवल एक शब्दकोश को बनाए रखने के लिए प्रतीत होता है, लेकिन मैं सोच रहा हूं कि इसके लिए एक और अधिक सुरुचिपूर्ण समाधान है या नहीं।

EDIT इसके लिए खेद है, मैं यह उल्लेख करना भूल गया कि मैं संपत्ति को केवल पढ़ने के लिए चाहता हूं।

+0

यह मेरे प्रश्नों का डुप्लिकेट हो सकता है: [अजगर आलसी संपत्ति डेकोरेटर] (http://stackoverflow.com/questions/3012421/python-lazy-property-decorator) – detly

+0

आप ठीक कह रहे हैं यह है। सुझाव-बॉक्स में इसे नहीं देखा। बंद करने के लिए वोटिंग। –

उत्तर

14

Denis Otkidach's CachedAttribute एक विधि सजावट है जो गुणों को आलसी बनाता है (एक बार गणना की जाती है, कई सुलभ होती है)। इसे केवल पढ़ने के लिए, मैंने __set__ विधि जोड़ा।

class ReadOnlyCachedAttribute(object):  
    '''Computes attribute value and caches it in the instance. 
    Source: Python Cookbook 
    Author: Denis Otkidach https://stackoverflow.com/users/168352/denis-otkidach 
    This decorator allows you to create a property which can be computed once and 
    accessed many times. Sort of like memoization 
    ''' 
    def __init__(self, method, name=None): 
     self.method = method 
     self.name = name or method.__name__ 
     self.__doc__ = method.__doc__ 
    def __get__(self, inst, cls): 
     if inst is None: 
      return self 
     elif self.name in inst.__dict__: 
      return inst.__dict__[self.name] 
     else: 
      result = self.method(inst) 
      inst.__dict__[self.name]=result 
      return result  
    def __set__(self, inst, value): 
     raise AttributeError("This property is read-only") 
    def __delete__(self,inst): 
     del inst.__dict__[self.name] 

उदाहरण के लिए:: पुनर्गणना के लिए क्षमता (नीचे देखें) बनाए रखने के लिए मैं एक __delete__ विधि जोड़ा

if __name__=='__main__': 
    class Foo(object): 
     @ReadOnlyCachedAttribute 
     # @read_only_lazyprop 
     def bar(self): 
      print 'Calculating self.bar' 
      return 42 
    foo=Foo() 
    print(foo.bar) 
    # Calculating self.bar 
    # 42 
    print(foo.bar)  
    # 42 
    try: 
     foo.bar=1 
    except AttributeError as err: 
     print(err) 
     # This property is read-only 
    del(foo.bar) 
    print(foo.bar) 
    # Calculating self.bar 
    # 42 

सुंदर चीजों के बारे में CachedAttribute (और ReadOnlyCachedAttribute) एक है अगर आप del foo.bar कि , अगली बार जब आप पहुंच foo.bar, मान फिर से गणना की जाती है। (यह जादू तथ्य यह है कि del foo.barfoo.__dict__ से 'bar' निकाल देता है लेकिन संपत्ति barFoo.__dict__ में रहता है ने संभव बनाया है।)

आप तो पुनर्गणना के लिए, इस क्षमता की जरूरत नहीं है या नहीं करना चाहते हैं निम्नलिखित (Mike Boers' lazyprop पर आधारित) केवल पढ़ने-योग्य आलसी संपत्ति बनाने का एक आसान तरीका है।

def read_only_lazyprop(fn): 
    attr_name = '_lazy_' + fn.__name__ 
    @property 
    def _lazyprop(self): 
     if not hasattr(self, attr_name): 
      setattr(self, attr_name, fn(self)) 
     return getattr(self, attr_name) 
    @_lazyprop.setter 
    def _lazyprop(self,value): 
     raise AttributeError("This property is read-only") 
    return _lazyprop 
+0

इसके लिए धन्यवाद। मैंने अपनी आवश्यकता को एक आवश्यकता जोड़ने के लिए संपादित किया था जिसे मैं भूल गया था। मैं इसे केवल पढ़ने के लिए कैसे बना सकता हूं? –

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