Propiedades no lo hacen automáticamente caché de sus valores de retorno. El getter (y setters) están destinados a ser llamados cada vez que se accede a la propiedad.
Sin embargo, Denis Otkidach ha escrito un decorador atributo de caché maravillosa (publicado en the Python Cookbook, 2nd edition y también originalmente en ActiveState bajo la PSF license) para este propósito:
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
Aquí es un ejemplo que demuestra su uso:
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()
decorador memoize es probablemente una exageración para una simple propiedad pitón. – SingleNegationElimination
También tenga en cuenta que, mientras tanto, está el decorador ['functools.lru_cache (maxsize = 128, typed = False)'] (https://docs.python.org/3/library/functools.html#functools.lru_cache) (que también permite un parámetro 'maxsize = None') –