【问题标题】:Labview-like behavior类似 Labview 的行为
【发布时间】: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_0output_1 只会启动相关计算。到目前为止,一切都很好......

不幸的是,发出

a.configure_traits()

并在对话框中更改 input_0 的值将进入 output_0output_1 的替代计算的无限递归。 traits.api 文档关于 on_trait_change 声明 如果当前线程是 UI 线程,则立即执行通知。这里我们处理的是属性,但它应该是类似的,因为 output_0_changed 通知在设置新值之前执行,因此 output_1 之间的递归调用output_0

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

【问题讨论】:

    标签: enthought traitsui


    【解决方案1】:

    部分解决方案是添加 _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 之前,一次在之后...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-15
      • 2012-01-28
      • 2011-05-12
      • 2016-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多