2011-06-21 17 views
15

Benim sorum şu tercümanın aynı iki kod çalıştırıyor:python: özellik alanları otomatik olarak önbelleğe alınır mı?

class A(object): 
    def __init__(self): 
    self.__x = None 

    @property 
    def x(self): 
    if not self.__x: 
     self.__x = ... #some complicated action 
    return self.__x 

ve çok daha basit:

class A(object): 
    @property 
    def x(self): 
     return ... #some complicated action 

I.e., x özelliğini önbelleğe alabilecek kadar akıllı olan yorumlayıcı mıdır?

Benim varsayımım x'in değişmediği - hard olduğunu bulmak, ama bir kez bulduktan sonra tekrar bulmak için bir sebep yok.

cevap

13

Hayır, alıcıya her eriştiğinizde çağrılacak.

17

Hayır sen memoize dekoratör eklemeniz gerekir:

class memoized(object): 
    """Decorator that caches a function's return value each time it is called. 
    If called later with the same arguments, the cached value is returned, and 
    not re-evaluated. 
    """ 
    def __init__(self, func): 
     self.func = func 
     self.cache = {} 
    def __call__(self, *args): 
     try: 
     return self.cache[args] 
     except KeyError: 
     value = self.func(*args) 
     self.cache[args] = value 
     return value 
     except TypeError: 
     # uncachable -- for instance, passing a list as an argument. 
     # Better to not cache than to blow up entirely. 
     return self.func(*args) 
    def __repr__(self): 
     """Return the function's docstring.""" 
     return self.func.__doc__ 
    def __get__(self, obj, objtype): 
     """Support instance methods.""" 
     return functools.partial(self.__call__, obj) 

@memoized 
def fibonacci(n): 
    "Return the nth fibonacci number." 
    if n in (0, 1): 
     return n 
    return fibonacci(n-1) + fibonacci(n-2) 

print fibonacci(12) 
+6

memoize dekoratör denemek

basit piton özelliği için muhtemelen overkill. – SingleNegationElimination

+1

Ayrıca, bu arada, ['functools.lru_cache (maxsize = 128, typed = False)'] (https://docs.python.org/3/library/functools.html#functools.lru_cache) dekoratörünün de bulunduğunu unutmayın. Ayrıca "maxsize = None" parametresine de izin verir) –

8

Özellikleri otomatik yok dönüş değerlerini önbelleğe. Alıcının (ve ayarlayıcıların), mülke her erişildiğinde çağrılması amaçlanmıştır.

Ancak Denis Otkidach sadece bu amaç için harika bir önbelleğe nitelik dekoratör (PSF license altında ActiveState üzerinde başlangıçta da the Python Cookbook, 2nd edition yayınlanan ve) yazmıştır:

: Burada
class cache(object):  
    '''Computes attribute value and caches it in the instance. 
    Python Cookbook (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): 
     # record the unbound-method and the name 
     self.method = method 
     self.name = name or method.__name__ 
     self.__doc__ = method.__doc__ 
    def __get__(self, inst, cls): 
     # self: <__main__.cache object at 0xb781340c> 
     # inst: <__main__.Foo object at 0xb781348c> 
     # cls: <class '__main__.Foo'>  
     if inst is None: 
      # instance attribute accessed on class, return self 
      # You get here if you write `Foo.bar` 
      return self 
     # compute, cache and return the instance's attribute value 
     result = self.method(inst) 
     # setattr redefines the instance's attribute so this doesn't get called again 
     setattr(inst, self.name, result) 
     return result 

kullanımını gösteren bir örnektir
def demo_cache(): 
    class Foo(object): 
     @cache 
     def bar(self): 
      print 'Calculating self.bar' 
      return 42 
    foo=Foo() 
    print(foo.bar) 
    # Calculating self.bar 
    # 42 
    print(foo.bar)  
    # 42 
    foo.bar=1 
    print(foo.bar) 
    # 1 
    print(Foo.bar) 
    # __get__ called with inst = None 
    # <__main__.cache object at 0xb7709b4c> 

    # Deleting `foo.bar` from `foo.__dict__` re-exposes the property defined in `Foo`. 
    # Thus, calling `foo.bar` again recalculates the value again. 
    del foo.bar 
    print(foo.bar) 
    # Calculating self.bar 
    # 42 

demo_cache() 
2

@ unutbu'nun cevabında adı geçen Denis Otkidach'ın dekoratörü O'Reilly'nin Python Yemek Kitabında yayınlandı. Ne yazık ki O'Reilly, kod örnekleri için herhangi bir lisans belirtmez - sadece kodu yeniden kullanmak için resmi olmayan izin olarak.

Liberal lisanslı önbelleğe alınmış bir özellik dekoratörüne ihtiyacınız varsa, ActiveState code recipes numaralı telefondan Ken Seehof ürününü @cached_property kullanabilirsiniz. Açıkça MIT license altında yayınlandı.

def cached_property(f): 
    """returns a cached property that is calculated by function f""" 
    def get(self): 
     try: 
      return self._property_cache[f] 
     except AttributeError: 
      self._property_cache = {} 
      x = self._property_cache[f] = f(self) 
      return x 
     except KeyError: 
      x = self._property_cache[f] = f(self) 
      return x 

    return property(get) 
+1

Ayrıca, bir Django projesi üzerinde çalışıyorsanız, '@ cached_property' öğesini' django.utils.functional''den içe aktarabilirsiniz. –

7

Python 3.2 itibaren bir LRU önbellek oluşturmak için kullanabileceğiniz yerleşik bir dekoratör sunmaktadır: Eğer Flask/Werkzeug kullanıyorsanız, Alternatif

@functools.lru_cache(maxsize=128, typed=False)

, @cached_property dekoratör var . Django için, from django.utils.functional import cached_property

+0

Ayrıca Django 'django.utils.functional import cached_property' –

İlgili konular