python: автоматически ли кэшируются поля свойств?

Мой вопрос в том, что следующие две части кода работают одинаково с интерпретатором:

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 

и намного проще:

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

То есть, интерпретатор достаточно умен, чтобы кэшировать свойство x ?

Мое предположение заключается в том, что x не меняется – найти это сложно , но как только вы его найдете один раз, нет никаких оснований его снова найти.

5 Solutions collect form web for “python: автоматически ли кэшируются поля свойств?”

Нет, получатель будет вызываться каждый раз, когда вы получаете доступ к свойству.

Нет, вам нужно добавить декоратор memoize :

 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) 

Свойства не кэшируют свои возвращаемые значения автоматически. Геттер (и сеттеры) предназначены для вызова каждый раз при доступе к свойству.

Тем не менее, Денис Откидах написал замечательный хранитель атрибутов кеширования (опубликованный в Поваренной книге Python, второе издание, а также первоначально на ActiveState под лицензией PSF ) для этой цели:

 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 

Вот пример, демонстрирующий его использование:

 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() 

Python 3.2 предлагает встроенный декоратор, который можно использовать для создания кеша LRU:

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

Кроме того, если вы используете Flask / Werkzeug, есть декоратор @cached_property .

Для Django попробуйте from django.utils.functional import cached_property

Декоратор Дениса Откидаха, упомянутый в ответе @ unutbu, был опубликован в Поваренной книге Python О'Рейли. К сожалению, O'Reilly не указывает какую-либо лицензию на примеры кода – так же, как неофициальное разрешение на повторное использование кода.

Если вам нужен декоратор с кешированными свойствами с либеральной лицензией, вы можете использовать @cached_property от Ken Seehof из рецептов кода ActiveState . Он явно опубликован под лицензией MIT .

 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) 
  • Как получить доступ к свойствам файла в Windows Vista с помощью Python?
  • бесконечная рекурсия в наборе python3.3
  • Путаница со свойствами
  • Как создать свойство класса только для чтения в Python?
  • Реализация свойства класса, которое сохраняет docstring
  • Как реализовать свойство () с динамическим именем (в python)
  • Проверка, может ли свойство настраиваться / удаляться
  • Создание свойств с использованием лямбда-геттера и сеттера
  • Python - лучший язык программирования в мире.