Чтобы обойти отсутствие установщика, вам придется напрямую манипулировать экземпляром __dict__
словаря.Однако вы не можете делать то, что хотите, с обычным property
объектом, потому что это дескриптор данных .Доступ к атрибутам всегда дает приоритет дескриптора данных над атрибутами экземпляра.
Вместо этого вам придется создать собственный дескриптор, который не определяет __set__
или __delete__
Метод:
class CachingProperty(object):
def __init__(self, fget):
self.name = fget.__name__
self.fget = fget
def __get__(self, instance, owner):
if instance is None:
return self
value = self.fget(instance)
instance.__dict__[self.name] = value
return value
Этот дескриптор также заботится об установке значения непосредственно в атрибуте экземпляра __dict__
, создавая таким образом атрибут экземпляра.
Используйте указанный выше класс вместо property
:
class A(object):
@CachingProperty
def x(self):
return "toto"
Демонстрация, показывающая, что метод получения вызывается только один раз:
>>> class Demo(object):
... @CachingProperty
... def foo(self):
... print("Calling the foo property")
... return "bar"
...
>>> d = Demo()
>>> d.foo
Calling the foo property
'bar'
>>> d.foo
'bar'
>>> vars(d)
{'foo': 'bar'}