回调与基于发电机的设计

时间:2013-11-07 19:39:47

标签: python callback generator class-design coroutine

我想得到你的设计建议。我有一个控制温度的烤箱,我正在做一些与温度有关的测量。我基本上是设定温度,测量一些东西然后继续前进。

我想出了两个简化的设计,如下所示。第一个使用基于回调的方法:

class Oven(object):
    # ... some methods
    def step_temperature(start, stop, num, rate, callback):
        temperatures = np.linspace(start, stop, num)
        for t in temperatures:
            self.temperature = t, rate # sweep to temperature with given rate
            self._wait_for_stability() # wait until temperature is reached.
            callback(t)                # execute the measurement
# Use Case
oven = Oven()
oven.step_temperature(start=20, stop=200, num=10, rate=1, callback=measure_stuff)

第二种设计是基于发电机的设计

class Oven(object):
    # ... some methods

    def step_temperature(start, stop, num, rate):
        temperatures = np.linspace(start, stop, num)
        for t in temperatures:
            self.temperature = t, rate
            self._wait_for_stability()
            yield t
# Use Case
oven = Oven()
for t in oven.step_temperature(start=20, stop=200, num=10, rate=1):
    measure_stuff(t)

我正在倾向于第二种设计,但我对你的建议感兴趣。如果有更好的方法,请不要犹豫告诉我。

2 个答案:

答案 0 :(得分:1)

@ P3trus。我最近在StackExchange的CodeReview上回答了一个非常类似的Python“yield vs. callback”问题。如果您想阅读here's a link,但我会总结一下:

有三种常用模式用于解决“报告反馈”要求:

  1. yield
  2. 回调函数
  3. 内联,硬编码反馈
  4. yield和回调都允许您将UI / IO的表示细节与模型或计算代码分开。这很好。两者都运作良好。

    如果你使用Python的yield,请确保你理解可迭代和生成器,因为有几种语言实现了yield关键字,但是如果你有例子,那么可能会有一些微妙的实现差异。习惯了C#的yield。这里是a reference - 它很微妙但值得一读。本质上,在Python函数产生时,它会返回一个生成器,该生成器可以有用地分配给变量,捕获迭代到那一点,但您可能想也可能不希望这样做。不要让那吓到你; yield很好。

    回调确实有一个很好的优势,它们允许返回到调用者(在模型或计算代码中),可用于暂停或停止处理或以其他方式向模型发送消息。这是一个很好的职责分离,如果你使用yield,它可以让沟通变得更加困难。或者可能不是。总会有办法的。 :)

    例如,在更新报告的温度时,回调还可以监视按钮或键并向调用者返回一个值,这可能表示用户想要中止处理,这不会污染模型特定的UI或IO。

    所以不仅仅是:

    callback(t)
    

    您可以让callback执行温度报告工作,但也可以听取用户收集的内容,例如:

    if callback(t) == ABORT_BUTTON_PRESSED:
        self.shutdown  # or whatever
    

    希望这有帮助。

答案 1 :(得分:0)

如果你每次拨打t偶尔会step_temperature做不同的事情,(就像你说的那样,以及一些结果,你会做一件事,而另一些你做另一件事) ,你想要发电机版本。如果每次调用step_temperature,你想要对每个项目做同样的事情,并且之间没有不同的计算,我会使用回调版本。这样,使用您的代码的任何人都不必知道何时调用t的处理函数。