Недавно я прошел существующую кодовую базу, содержащую много классов, где атрибуты экземпляра отражают значения, сохраненные в базе данных. Я осуществил рефакторинг много этих атрибутов, чтобы иметь их поиски базы данных быть задержанным, т.е. не быть инициализированным в конструкторе, но только после первого чтения. Эти атрибуты не переключают время жизни экземпляра, но они - реальное узкое место, чтобы вычислить, что в первый раз и только действительно получил доступ для особых случаев. Следовательно они могут также кэшироваться после того, как они были получены от базы данных (это поэтому соответствует определению memoisation, где вход не является просто "никаким входом").
Я ввожу следующий отрывок кода много раз для различных атрибутов через различные классы:
class testA(object):
def __init__(self):
self._a = None
self._b = None
@property
def a(self):
if self._a is None:
# Calculate the attribute now
self._a = 7
return self._a
@property
def b(self):
#etc
Существует ли существующий декоратор уже, чтобы сделать это в Python, о котором я просто не знаю? Или, существует ли довольно простой способ определить декоратора, который делает это?
Я работаю в соответствии с Python 2.5, но 2,6 ответа могли бы все еще быть интересными, если они существенно отличаются.
Этот вопрос задали, прежде чем Python включал много готовых декораторов для этого. Я обновил его только для исправления терминологии.
Вот пример реализации ленивого декоратора свойств:
import functools
def lazyprop(fn):
attr_name = '_lazy_' + fn.__name__
@property
@functools.wraps(fn)
def _lazyprop(self):
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self))
return getattr(self, attr_name)
return _lazyprop
class Test(object):
@lazyprop
def a(self):
print 'generating "a"'
return range(5)
Интерактивная сессия:
>>> t = Test()
>>> t.__dict__
{}
>>> t.a
generating "a"
[0, 1, 2, 3, 4]
>>> t.__dict__
{'_lazy_a': [0, 1, 2, 3, 4]}
>>> t.a
[0, 1, 2, 3, 4]
свойство
- это класс. Дескриптор , если быть точным. Просто сделайте вывод из этого и реализуйте желаемое поведение.
class lazyproperty(property):
....
class testA(object):
....
a = lazyproperty('_a')
b = lazyproperty('_b')