2010-07-13 16 views
7

Tôi muốn tạo trang trí hoạt động giống như thuộc tính, chỉ gọi hàm trang trí một lần và các cuộc gọi tiếp theo luôn trả về kết quả của cuộc gọi đầu tiên. Ví dụ:Cách tạo trình trang trí để khởi tạo lười của thuộc tính

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

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

Ý tưởng của tôi là viết một trang trí tùy chỉnh cho việc này. Vì vậy, tôi bắt đầu, và điều này là như thế nào đến nay tôi đến:

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? 

Như bạn thấy, tôi không biết nơi để lưu trữ giá trị được lưu trữ. Giải pháp đơn giản nhất có vẻ là chỉ duy trì một từ điển, nhưng tôi tự hỏi nếu có một giải pháp thanh lịch hơn cho việc này.

EDIT Xin lỗi vì điều đó, tôi quên đề cập đến rằng tôi muốn thuộc tính chỉ đọc.

+0

Đây có thể là một bản sao của câu hỏi của tôi: [Python sở hữu lười biếng trang trí] (http://stackoverflow.com/questions/3012421/python-lazy-property-decorator) – detly

+0

Bạn nói đúng nó được. Không nhìn thấy nó trong hộp gợi ý. Bỏ phiếu để đóng. –

Trả lời

14

Denis Otkidach's CachedAttribute là một trình trang trí phương pháp khiến các thuộc tính lười (được tính một lần, có thể truy cập nhiều). Để làm cho nó cũng chỉ đọc, tôi đã thêm một phương thức __set__. Để duy trì khả năng tính toán lại (xem dưới đây) Tôi đã thêm một phương pháp __delete__:

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] 

Ví dụ:

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 

Một trong những điều đẹp về CachedAttribute (và ReadOnlyCachedAttribute) là nếu bạn del foo.bar , sau đó lần sau bạn truy cập foo.bar, giá trị được tính lại. (Ma thuật này được thực hiện bởi thực tế là del foo.bar loại bỏ 'bar' từ foo.__dict__ nhưng tài sản bar vẫn còn trong Foo.__dict__.)

Nếu bạn không cần hoặc không muốn khả năng này để tính toán lại, thì sau đây (dựa trên Mike Boers' lazyprop) là cách đơn giản hơn để tạo tài sản lười biếng chỉ đọc.

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

Cảm ơn vì điều đó. Tôi vừa chỉnh sửa câu hỏi của mình để thêm một yêu cầu mà tôi đã quên. Làm thế nào tôi có thể làm cho chỉ đọc này? –

Các vấn đề liên quan