7.10 带额外状态信息的回调函数
问题
你的代码中需要依赖到回调函数的使用(比如事件处理器、等待后台任务完成后的回调等), 并且你还需要让回调函数拥有额外的状态值,以便在它的内部使用到。
解决方案
这一小节主要讨论的是那些出现在很多函数库和框架中的回调函数的使用——特别是跟异步处理有关的。
为了让回调函数访问外部信息,一种方法是使用一个绑定方法来代替一个简单函数。 比如,下面这个类会保存一个内部序列号,每次接收到一个 result
的时候序列号加1:
使用这个类的时候,你先创建一个类的实例,然后用它的 handler()
绑定方法来做为回调函数:
第二种方式,作为类的替代,可以使用一个闭包捕获状态值,例如:
下面是使用闭包方式的一个例子:
还有另外一个更高级的方法,可以使用协程来完成同样的事情:
对于协程,你需要使用它的 send()
方法作为回调函数,如下所示:
讨论
基于回调函数的软件通常都有可能变得非常复杂。一部分原因是回调函数通常会跟请求执行代码断开。 因此,请求执行和处理结果之间的执行环境实际上已经丢失了。如果你想让回调函数连续执行多步操作, 那你就必须去解决如何保存和恢复相关的状态信息了。
至少有两种主要方式来捕获和保存状态信息,你可以在一个对象实例(通过一个绑定方法)或者在一个闭包中保存它。 两种方式相比,闭包或许是更加轻量级和自然一点,因为它们可以很简单的通过函数来构造。 它们还能自动捕获所有被使用到的变量。因此,你无需去担心如何去存储额外的状态信息(代码中自动判定)。
如果使用闭包,你需要注意对那些可修改变量的操作。在上面的方案中, nonlocal
声明语句用来指示接下来的变量会在回调函数中被修改。如果没有这个声明,代码会报错。
而使用一个协程来作为一个回调函数就更有趣了,它跟闭包方法密切相关。 某种意义上来讲,它显得更加简洁,因为总共就一个函数而已。 并且,你可以很自由的修改变量而无需去使用 nonlocal
声明。 这种方式唯一缺点就是相对于其他Python技术而言或许比较难以理解。 另外还有一些比较难懂的部分,比如使用之前需要调用 next()
,实际使用时这个步骤很容易被忘记。 尽管如此,协程还有其他用处,比如作为一个内联回调函数的定义。
如果你仅仅只需要给回调函数传递额外的值的话,还有一种使用 partial()
的方式也很有用。
Last updated
Was this helpful?