【问题标题】:callback vs generator based design回调与基于生成器的设计
【发布时间】:2013-11-19 15:20:23
【问题描述】:

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

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

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)

我倾向于第二种设计,但我对您的建议很感兴趣。如果有更好的方法,请随时告诉我。

【问题讨论】:

  • 这两个实现有很多不同的属性。第一个是“阻塞”,而第二个允许停止和恢复计算(这可能是也可能不是你想要的)。如果您总是在 for x in the_generator(): callback(x) 中使用它,那么我认为没有理由使用生成器,只需在方法中调用 callback
  • 生成器很适合实现花哨的算法。但是为了自动化一些测量,这通常是一些基于时间的过程,我会坚持标准的过程代码,所以我的投票是第一个解决方案。

标签: python callback generator class-design coroutine


【解决方案1】:

@P3trus。我最近在 StackExchange 的 CodeReview 上回答了一个非常相似的 Python“收益与回调”问题。如果您想阅读它,here's a link 但我会总结一下:

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

  1. yield
  2. 回调函数
  3. 内嵌硬编码反馈

yield 和回调都允许您将 UI/IO 的表示细节与模型或计算代码分开。这很好。两者都运作良好。

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

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

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

所以不仅仅是:

callback(t)

您可以让callback 完成它的温度报告工作,但也可以听取它可能从用户那里收集到的信息,例如:

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

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    如果你偶尔在每次调用step_temperature 时用t 做不同的事情,(比如,你调用它,并且一些结果,你做一件事,而有些你做另一件事),你会想要生成器版本。如果每次调用step_temperature 时,您都希望对每个项目执行相同的操作,并且两者之间没有不同的计算,我会使用回调版本。这样,任何使用您的代码的人都不必知道何时为t 调用他们的处理函数。

    【讨论】:

      猜你喜欢
      • 2016-08-25
      • 2015-12-11
      • 2011-08-07
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 2013-03-07
      • 1970-01-01
      相关资源
      最近更新 更多