確かに、インスタンスは、それは以降のアクセスで返される属性だけで、あなたのプロパティが設定されています
class Foo(object):
_cached_bar = None
@property
def bar(self):
if not self._cached_bar:
self._cached_bar = self._get_expensive_bar_expression()
return self._cached_bar
property
記述子は、データディスクリプタ(__get__
,__set__
、__delete__
の記述子フックを実装している)ので、インスタンスにbar
属性が存在していても呼び出されます。その結果、Pythonはその属性を無視します。 attrib各アクセス時にute。
あなたはそれが存在する場合、Pythonは、ディスクリプタを超えるインスタンスの属性を使用して、その時点で、唯一の__get__
を実装する独自の記述子を書き込むことができます。
class CachedProperty(object):
def __init__(self, func, name=None):
self.func = func
self.name = name if name is not None else func.__name__
self.__doc__ = func.__doc__
def __get__(self, instance, class_):
if instance is None:
return self
res = self.func(instance)
setattr(instance, self.name, res)
return res
class Foo(object):
@CachedProperty
def bar(self):
return self._get_expensive_bar_expression()
あなたが何かをしてい__getattr__
アプローチを(希望する場合それを言う)、それはなるだろう:
class Foo(object):
def __getattr__(self, name):
if name == 'bar':
bar = self.bar = self._get_expensive_bar_expression()
return bar
return super(Foo, self).__getattr__(name)
以降のアクセスでは、インスタンスと__getattr__
上bar
属性が相談されることはありませんでしょう。
デモ:
>>> class FooExpensive(object):
... def _get_expensive_bar_expression(self):
... print 'Doing something expensive'
... return 'Spam ham & eggs'
...
>>> class FooProperty(FooExpensive):
... _cached_bar = None
... @property
... def bar(self):
... if not self._cached_bar:
... self._cached_bar = self._get_expensive_bar_expression()
... return self._cached_bar
...
>>> f = FooProperty()
>>> f.bar
Doing something expensive
'Spam ham & eggs'
>>> f.bar
'Spam ham & eggs'
>>> vars(f)
{'_cached_bar': 'Spam ham & eggs'}
>>> class FooDescriptor(FooExpensive):
... bar = CachedProperty(FooExpensive._get_expensive_bar_expression, 'bar')
...
>>> f = FooDescriptor()
>>> f.bar
Doing something expensive
'Spam ham & eggs'
>>> f.bar
'Spam ham & eggs'
>>> vars(f)
{'bar': 'Spam ham & eggs'}
>>> class FooGetAttr(FooExpensive):
... def __getattr__(self, name):
... if name == 'bar':
... bar = self.bar = self._get_expensive_bar_expression()
... return bar
... return super(Foo, self).__getatt__(name)
...
>>> f = FooGetAttr()
>>> f.bar
Doing something expensive
'Spam ham & eggs'
>>> f.bar
'Spam ham & eggs'
>>> vars(f)
{'bar': 'Spam ham & eggs'}
あなたが記述子と自動的にそれを行うことができます。http://jeetworks.org/node/62 – schlamar
WERKZEUGは広範でより良い実装を持っていますコメント:https://github.com/mitsuhiko/werkzeug/blob/10b4b8b6918a83712170fdaabd3ec61cf07f23ff/werkzeug/utils.py#L35 – schlamar
も参照してください:[Python lazy property decorator](http://stackoverflow.com/questions/3012421/python-怠惰なプロパティデコレータ)。 – detly