类似Labview的行为

时间:2017-09-25 16:35:55

标签: enthought traitsui

我想要一个带输入和输出的对象,所有输出仅在需要时计算(某些输出可能仅取决于部分输入集等),如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

到目前为止,我没有找到任何解决方法来摆脱这种递归。有什么想法吗?

1 个答案:

答案 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 ,一次调用...