看到标题大家可能都会觉得很简单,但是事实并非如此,接下来我们一起细细看来。
第一种回调:看到标题后你的第一反应
def handler(x):
print("The result is ", x)
def add(a, b):
return a + b
def task_async(func, args, *, callback=None):
result = func(*args)
callback(result)
if __name__ == "__main__":
task_async(add, (2, 3), callback=handler)
超级简单的回调模型。
第二种回调:带外部状态的回调
class RequestHandler:
def __init__(self):
self.sequence = 0
def handler(self, result):
self.sequence += 1
print("[{}] Got: {}".format(self.sequence, result))
def add(a, b):
return a + b
def task_async(func, args, *, callback=None):
result = func(*args)
callback(result)
if __name__ == "__main__":
request = RequestHandler()
task_async(add, (2, 3), callback=request.handler)
task_async(add, ("hi", " nihao"), callback=request.handler)
通过类变量来让回调函数带上外部状态
另外,我们还可以通过闭包来实现。
def make_handler():
sequence = 0
def handler(result):
nonlocal sequence
sequence += 1
print("[{}] Got {}".format(sequence, result))
return handler
def add(a, b):
return a + b
def task_async(func, args, *, callback=None):
result = func(*args)
callback(result)
if __name__ == "__main__":
handler = make_handler()
task_async(add, (2, 3), callback=handler)
task_async(add, ("hi", " nihao"), callback= handler)
其实闭包和简单的类时可以向上面互换的。
第三种回调:利用协程(高端大气)
def make_handler():
sequence = 0
while True:
result = yield
sequence += 1
print("[{}] Got {}".format(sequence, result))
def add(a, b):
return a + b
def task_async(func, args, *, callback=None):
result = func(*args)
callback(result)
if __name__ == "__main__":
handler = make_handler()
next(handler)
task_async(add, (2, 3), callback=handler.send)
task_async(add, ("hi", " nihao"), callback= handler.send)
好了,协程这个非常巧妙。
第四种回调:内联回调,基于协程和生成器
from queue import Queue
from functools import wraps
class Async:
def __init__(self, func, args):
self.func = func
self.args = args
def inlined_async(func):
@wraps(func)
def wrapper(*args):
f = func(*args)
result_queue = Queue()
result_queue.put(None)
while True:
result = result_queue.get()
try:
a = f.send(result)
task_async(a.func, a.args, callback=result_queue.put)
except StopIteration:
break
return wrapper
def add(a, b):
return a + b
@inlined_async
def test():
r = yield Async(add, (2, 3))
print(r)
r = yield Async(add, ("hi", "hajimemashite"))
print(r)
for n in range(10):
r = yield Async(add, (n, n))
print(r)
print("Goodbye")
def task_async(func, args, *, callback=None):
result = func(*args)
callback(result)
这个例子略微复杂,需要的python知识比较多。通过这样设计,所有的回调都在内部进行消化。使用起来感觉不到回调。
根据第一性原理,凡事需要思考本质。其实回调的本质是一个生产者和消费者模型的设计。这样我们就可以拓开思路。Do not repeat yourself.