Laurens Koppenol建議使用properties
(Python對計算屬性的一般支持),這是一個好主意,但他的示例代碼在許多方面都被破壞並且比它更復雜,所以這裏有一個更簡單的工作和pythonic示例(無Updatable
類,也沒有任何其他多餘的東西需要):
class Rectangle(object):
def __init__(self, length, perimeter):
self.length = length
self.perimeter = perimeter
@property
def width(self):
return 0.5*(self.perimeter - 2.*self.length)
如果你想緩存width
值(以避免無用計算),但仍使當length
或perimeter
變化,你需要確保它的更新使他們全部屬性:
class Rectangle(object):
def __init__(self, length, perimeter):
self.length = length
self.perimeter = perimeter
@property
def length(self):
return self._length
@length.setter
def length(self, value):
self._length = value
self._width = None
@property
def perimeter(self):
return self._perimeter
@length.setter
def perimiter(self, value):
self._perimeter = value
self._width = None
@property
def width(self):
if self._width is None:
self._width = 0.5*(self.perimeter - 2.*self.length)
return self._width
或者(如果你有很多這樣的東西)使用一些「cached_property與失效」的實施,因爲這一個:Storing calculated values in an object
編輯:WRT /你的問題,調用locals
的確是醜(和可能很容易中斷 - 你可能有本地變量,不應該是_vars
的一部分),以及需要在子類中明確設置self._vars
。另外update()
API本身相當醜陋恕我直言。現在你不需要任何幻想,使整個事情更Python - 這裏有一個解決方案的唯一樣板是需要調用Updateable.__init__
與命名的參數(不帶位置的人的工作):
class Updateable(object):
def __init__(self, **kwargs):
self._vars = kwargs
def update(self, **kwargs):
vars = self._vars.copy()
vars.update(**kwargs)
self.__init__(**vars)
class Rectangle(Updateable):
def __init__(self, length, perimeter):
super(Rectangle, self).__init__(length=length, perimeter=perimeter)
self.length = length
self.width = 0.5*(perimeter - 2.*length)
r = Rectangle(10, 20)
r.update(perimeter=40)
作爲側面說明,我personnaly發現很令人不安,你的Rectangle
類需要perimeter
論點,但存儲width
而不是...也許你應該考慮perimeter
屬性? (即使只讀,以避免重新計算等)
對象已存在後調用__init__似乎有點奇怪。爲什麼不只是一個'recalculate_width'方法呢? – BrenBarn
因爲我希望它適用於我有的其他類,它們都有不同的參數名稱。有時它是'寬度',有時它是'角度',有時它是'波長',可能是任何東西。 –