【发布时间】:2017-09-25 16:35:54
【问题描述】:
我想要一个具有输入和输出的对象,所有输出仅在需要时计算(某些输出可能仅取决于部分输入集等),就像在 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 的值 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 文档关于 on_trait_change 声明 如果当前线程是 UI 线程,则立即执行通知。这里我们处理的是属性,但它应该是类似的,因为 output_0_changed 通知在设置新值之前执行,因此 output_1 之间的递归调用 和 output_0
到目前为止,我还没有找到任何解决方案来摆脱这种递归。有什么想法吗?
【问题讨论】: