我有一个类实例,其属性是根据其他属性计算得出的。这些属性将在实例的整个生命周期中发生变化。所有属性不一定是在对象初始化时定义的。
从其他属性计算属性的Pythonic方法是什么?
这是一个简单的例子,计算有许多输入变量(下面的“a”)和计算(“b”和“c”)。
a = something
b = function of a (a+5)
c = function of a and b (a*b)
我已经尝试了很多实现。这是一个很好的表达我意图的方式。
class CalcAttr(object):
def __init__(self):
self._a = None
self._b = None
self._c = None
@property
def a(self):
return self._a
@a.setter
def a(self,value):
self._a = value
@property
def b(self):
self.calc_b()
return self._b
@property
def c(self):
self.calc_c()
return self._c
def calc_b(self):
self._b = self._a + 5
def calc_c(self):
self._c = self._a * self._b
def test():
abc = CalcAttr()
a = 5
return abc.c
注意:如果我先调用 t.b,则 t.c 可以工作。
> >>> t=abc.test()
> >>> t.c Traceback (most recent call last): File "<stdin>", line 1, in <module> File "abc.py", line 22, in c
> self.calc_c() File "abc.py", line 29, in calc_c
> self._c = int(self._a) * int(self._b) TypeError: int() argument must be a string or a number, not 'NoneType'
> >>> t.b 10
> >>> t.c 50
> >>>
请记住,大多数实际计算都依赖于多个属性(5-10 个输入变量和尽可能多的计算变量)。
我的下一次迭代将包括一个“calculate_model”函数,该函数将在检查所有输入均已定义后填充所有计算属性。也许这将是 pyhonic 答案?
谢谢!
更新 - 工作解决方案
我创建了一个按顺序计算每个属性的方法:
def calc_model(self):
self.calc_b()
self.calc_c()
每个计算属性都会调用该方法
@property
def c(self):
self.calc_model()
return self._c
我不确定这是否正确,但它按预期工作......
如果我正确理解你的问题,你应该在它们的吸气剂中计算
b
和 c
。您可能还应该要求用户在初始化程序中传递 a
的值,因为没有 b
就无法计算 c
和 a
。另外,似乎没有太多理由保留 _a
、_b
和 _c
——除非 b
和 c
的计算成本很高并且您想要缓存他们。
例如:
class CalcAttr(object):
def __init__(self, a):
self.a = a
@property
def b(self):
return self.a + 5
@property
def c(self):
return self.a * self.b
这样
>>> x = CalcAttr(42)
>>> x.c
1974
我理解@jme在接受的答案中建议的内容更优雅,但我仍然尝试修复原始示例并使其正常工作。这是代码。
class CalcAttr(object):
def __init__(self):
self._a = None
self._b = None
self._c = None
@property
def a(self):
return self._a
@a.setter
def a(self,value):
self._a = value
@property
def b(self):
self.calc_b()
return self._b
@property
def c(self):
self.calc_c()
return self._c
def calc_b(self):
self._b = self._a + 5
def calc_c(self):
self._c = self.a * self.b
def test():
abc = CalcAttr()
abc.a = 5
return abc.c
test()
代码将起作用,
50
是结果值。
我多次需要这个,所以我尝试为其创建一个解决方案。 @compulated_property 可以像这样使用:
class CalcAttr(object, has_computed_properties):
a: int
@computed_property
def b(self):
return self.a + 5
@computed_property
def c(self):
return self.a * self.b
# test
class TestComputedProperty(unittest.TestCase):
def test_so_issue(self):
so = CalcAttr()
so.a = 5
self.assertEqual(so.b, 10)
self.assertEqual(so.c, 50)
$ python3 computed_tests.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK