简体   繁体   English

回调与基于生成器的设计

[英]callback vs generator based design

I'd like to get your advice for a design. 我想获得您的设计建议。 I've got an Oven controlling the temperature and I'm doing some temperature dependent measurements. 我有一个烤箱控制温度,并且正在执行一些温度相关的测量。 I'm basically setting the temperature, measure some stuff and move on. 我基本上是在设定温度,测量一些东西然后继续前进。

I came up with two designs, simplified of course, which are shown below. 我想出了两种设计,它们当然经过了简化,如下所示。 The first one uses a callback based approach: 第一个使用基于回调的方法:

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)

The second design is a generator based design 第二种设计是基于发电机的设计

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)

I'm tending towards the second design, but I'm interrested in your suggestions. 我正在尝试第二个设计,但是我对您的建议很感兴趣。 If there is a even better way don't hesitate to tell me. 如果有更好的方法,请随时告诉我。

@P3trus. @ P3trus。 I recently answered a very similar Python "yield versus callback" question on StackExchange's CodeReview. 我最近在StackExchange的CodeReview上回答了一个非常类似的Python“收益与回调”问题。 If you want to read it, here's a link but I'll summarize: 如果您想阅读, 这里是一个链接,但我总结一下:

There are three common patterns used to solve the "report feedback" requirement: 有三种常见的模式可用来解决“报告反馈”的要求:

  1. yield
  2. a callback function 回调函数
  3. inline, hard-coded feedback 内联,硬编码的反馈

Both yield and callbacks allow you to separate the presentation details of UI/IO from the model or computation code. yield和回调都允许您将UI / IO的表示详细信息与模型或计算代码分开。 This is good. 很好 Both work well. 两者都运作良好。

If you go with Python's yield , ensure you understand iterables and generators well, since several languages implement a yield keyword but have subtle implementation differences that might surprise you if, for example, you're used to C#'s yield . 如果您使用Python的yield ,请确保您很好地理解了可迭代对象和生成器,因为多种语言实现了yield关键字,但实现方面的细微差别可能会使您感到惊讶,例如,如果您习惯于C#的yield Here's a reference on that -- it's subtle but worth reading. 这是一个参考 ,虽然有些微妙但值得一读。 Essentially, in Python when your function yields, it returns a generator which can be usefully assigned to a variable, capturing iteration to that point, but you may or may not want to do that. 本质上,在Python中,当函数产生时,它会返回一个生成器,该生成器可以有效地分配给变量,从而捕获到该点的迭代,但是您可能想要也可能不想这样做。 Don't let that scare you; 不要让那吓到你; yield is good. yield好。

Callbacks do have a nice advantage in that they allow communication back to the caller (in the model or computational code) which can be used to pause or halt processing or otherwise send a message to the model. 回调确实有一个很好的优点,因为它们允许通信返回给调用者(在模型或计算程序),它可以用来暂停或停止处理或以其他方式将消息发送到模型。 This is a nice separation of duties and it allows communication that may be more difficult if you use yield . 这是很好的职责分离,如果您使用yield 则允许进行交流可能会更加困难。 Or maybe not. 或者可能不是。 There is always a way. 总会有办法的。 :) :)

For example, while updating the reported temperature the callback can also monitor buttons or keys and return a value to the caller which could indicate, for example, that the user wants to abort processing and this doesn't pollute the model with awareness of specific UI or IO. 例如,在更新报告的温度时,回调还可以监视按钮或按键,并向调用方返回一个值,该值可以指示例如用户想要中止处理,并且这不会污染具有特定UI的模型。或IO。

So instead of just: 因此,不仅仅是:

callback(t)

You can let callback do its temperature reporting job but also listen to what it may have collected from the user, such as: 您可以让callback执行其温度报告工作,还可以侦听它可能从用户那里收集的内容,例如:

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

Hope this helps. 希望这可以帮助。

If you occasionally do different stuff with t per call of step_temperature , (like, you call it, and some of the results, you do one thing with, while some you do another with), you'd want the generator version. 如果您偶尔会在每次调用step_temperaturet做不同的事情(例如,您调用它,并且在某些结果中,您使用一件事,而在另一些结果中使用另一件事),则需要生成器版本。 If every time you call step_temperature , you want the same thing done to every item, and no differing computation between, I'd use the callback version. 如果每次调用step_temperature ,都希望对每个项目执行相同的操作,并且两者之间没有不同的计算,那么我将使用回调版本。 That way anyone who uses your code doesn't have to know when to call their processing function for t . 这样,使用您的代码的任何人都不必知道何时为t调用其处理函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM