【发布时间】:2019-12-17 17:36:10
【问题描述】:
我正在编写一个具有各种属性的类,我只想在必要时进行计算(惰性评估)。但是,更重要的是,我想确保如果它们的计算所依赖的任何属性发生更改,则不会返回“陈旧”值。除了实现某种计算图(有没有办法做到这一点?)除了这涉及到很多setter方法以及相关计算的手动编码重置之外,我想不出任何好的方法价值观。
有没有更简单/更好或更不容易出错的方法来做到这一点? (我正在处理的实际应用程序比这个更大的计算图更复杂)
from math import pi
class Cylinder:
def __init__(self, radius, length, density):
self._radius = radius
self._length = length
self._density = density
self._volume = None
self._mass = None
@property
def volume(self):
if self._volume is None:
self._volume = self.length*pi*self.radius**2
print("Volume calculated")
return self._volume
@property
def mass(self):
if self._mass is None:
self._mass = self.volume*self.density
print("Mass calculated")
return self._mass
@property
def length(self):
return self._length
@length.setter
def length(self, value):
self._length = value
self._volume = None
self._mass = None
print("Volume and mass reset")
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
self._radius = value
self._volume = None
self._mass = None
print("Volume and mass reset")
@property
def density(self):
return self._density
@density.setter
def density(self, value):
self._density = value
self._mass = None
print("Mass reset")
(打印语句仅供解释)
这行得通。在解释器中:
>>> c = Cylinder(0.25, 1.0, 450)
>>> c.radius
0.25
>>> c.length
1.0
>>> c.density
450
>>> c.volume
Volume calculated
0.19634954084936207
>>> c.mass
Mass calculated
88.35729338221293
>>> c.length = c.length*2 # This should change things!
Volume and mass reset
>>> c.mass
Volume calculated
Mass calculated
176.71458676442586
>>> c.volume
0.39269908169872414
>>>
我能找到的最接近的答案是this one,但我认为这是用于记忆函数结果而不是属性值。
【问题讨论】:
-
...attributes that their calculation depended...- 它们都是实例/类属性吗? -
我只是在大声思考:
Cylinder是否需要是可变对象?也许您可以使其不可变并在某些属性更改时返回新的Cylinder。 -
@wwii 是的,在我的应用程序中它们都是类属性。
-
@AndrejKesely 我实际使用的类有很多东西(其他属性和附加的东西)所以我不认为每次任何属性更改都从头开始重新生成它不会成为一个解决方案。
-
有关更多背景信息,我正在使用的真实对象是一个随时间演变的仿真模型。每次迭代都会发生变化,但并非所有属性都需要重新计算(取决于用户在做什么),我希望获得最大的模拟速度。
标签: python properties lazy-evaluation memoization getattribute