我想要一个带输入和输出的对象,所有输出仅在需要时计算(某些输出可能仅取决于部分输入集等),如Labview VI中所示。输出之间可能存在级联关系,例如output_1的计算结果取决于output_0的计算结果。
让我们考虑这个过于简单的例子(我意识到output_0和output_1可以在一个程序中计算,但我的目标是更复杂的应用程序):
from traits.api import HasTraits, Int, Property, cached_property
class A(HasTraits):
input_0 = Int
output_0 = Property(depends_on='input_0')
output_1 = Property(depends_on='output_0')
@cached_property
def _get_output_0(self):
print('_get_output_0')
return self.input_0**2
@cached_property
def _get_output_1(self):
print('_get_output_1')
return self.output_0**2
a = A(input_0=3)
这里的问题是,由于 output_1 被声明依赖于 output_0 ,因此每次都必须计算 output_0 的值< strong> input_0 更改(这是可以理解的),即我们在执行上述代码时打印了'_get_output_0'。
使用事件可以获得更一致的行为,如:
from traits.api import HasTraits, Int, Property, cached_property, Event
from traitsui.api import View
class A(HasTraits):
input_0 = Int
output_0 = Property(depends_on='input_0')
output_1 = Property(depends_on='output_0_changed') # <--- depends on Event now ---
output_0_changed = Event
@cached_property
def _get_output_0(self):
print('_get_output_0')
self.output_0_changed = True # <----- Event fired ----------
return self.input_0**2
@cached_property
def _get_output_1(self):
print('_get_output_1')
return self.output_0**2
traits_view = View('input_0', 'output_0', 'output_1')
a = A(input_0=3)
乌拉! output_0 的计算不再被解雇。以任何顺序询问 output_0 或 output_1 将仅启动相关计算。到目前为止,这么好......
不幸的是,发出
a.configure_traits()
并在对话框中更改 input_0 的值将进入 output_0 和 output_1 的替代计算的无限递归。 traits.api doc说明 on_trait_change 如果当前线程是UI线程,则立即执行通知。这里我们处理的是Property,但它应该是类似的,如果 output_0_changed 通知在设置新值之前执行,因此 output_1之间的递归调用和 output_0
到目前为止,我没有找到任何解决方法来摆脱这种递归。有什么想法吗?
答案 0 :(得分:0)
部分解决方案是添加 _output_0 特征,并使 output_1 依赖于 _output_0 :
from traits.api import HasTraits, Int, Property, cached_property
from traitsui.api import View
class A(HasTraits):
_output_0 = Int
input_0 = Int
output_0 = Property(depends_on='input_0')
output_1 = Property(depends_on='_output_0')
@cached_property
def _get_output_0(self):
print('_get_output_0')
self._output_0 = self.input_0**2
return self._output_0
@cached_property
def _get_output_1(self):
print('_get_output_1')
return self.output_0**2
traits_view = View('input_0', 'output_0', 'output_1')
a = A(input_0=3)
但是,如果打开配置对话框,则更改输入会使 _get_output_0 调用两次,一次调用 _get_output_1 ,一次调用...