Вот ваш класс, использующий вместо этого свойства (с добавленным методом для возврата каждого свойства):
Class PropertyComputer:
def __init__(self, x):
self._x = x
@property
def prop1(self):
return self._x
@property
def prop2(self):
return self._x * self._x
@property
def prop3(self):
return self.prop1 + self.prop2
def get_props(self):
return self.prop1, self.prop2, self.prop3
По дизайну я считаю, что это лучше, потому что:
- хранение
x
в качестве переменной экземпляра имеет больше смысла: смысл использования объектов состоит в том, чтобы избежать необходимости передавать переменные, особенно те, которые сам объект может отслеживать; - назначение атрибута и его соответствующие вычисления связаны друг с другом в каждом методе, декорированном свойством: нам никогда не придется думать, в чем проблема - в методе init (где вы определяете атрибут) или в методе compute (где выложена логика c для вычисления атрибута ).
Обратите внимание, что концепция «сначала вычислить помощников, а затем свойства в зависимости от них» на самом деле не применима к этому коду: нам нужно только оценить prop3
, если / когда нам действительно нужно Это. Если мы никогда не обращаемся к нему, нам никогда не нужно его вычислять.
«Плохой» побочный эффект использования свойств по сравнению с вашим примером состоит в том, что эти свойства нигде не «хранятся» (поэтому я и добавил последний метод):
c = PropertyComputer(x=2)
c.__dict__ # outputs {'_x': 2}
Также обратите внимание, что при использовании декораторов атрибуты вычисляются на лету при каждом обращении к ним вместо одного раза в методе init. Таким образом, методы, украшенные свойствами, работают как методы, но к ним обращаются как к атрибутам (суть их использования):
c = PropertyComputer(x=2)
c.prop1 # outputs 2
c._x = 10
c.prop1 # outputs 10
В качестве примечания можно использовать functools.cached_property
для кэширования оценки одного из этих свойств, в случае, если оно требует больших вычислительных ресурсов.