返回顶部

python 实用编程技巧 —— 带额外状态信息的回调函数

带额外状态信息的回调函数

问题

你的代码中需要依赖到回调函数的使用(比如事件处理器、等待后台任务完成后的回调等), 并且你还需要让回调函数拥有额外的状态值,以便在它的内部使用到。

解决方案

调用回调函数的函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 异步回调
 
def apply_async(func, args, *, callback):
    # Compute the result
    result = func(*args)
 
    # Invoke the callback with the result
    callback(result)
 
def print_result(result):
    print('Got:', result)
 
def add(x, y):
    return x + y
 
res = apply_async(add, (2, 3), callback=print_result)
apply_async(add, ('hello', 'world'), callback=print_result)

  

 

 注意到 print_result() 函数仅仅只接受一个参数 result 。不能再传入其他信息。 而当你想让回调函数访问其他变量或者特定环境的变量值的时候就会遇到麻烦。

为了让回调函数访问外部信息,一种方法是使用一个绑定方法来代替一个简单函数。 比如,下面这个类会保存一个内部序列号,每次接收到一个 result 的时候序列号加1

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 异步回调
class ResultHandler:
    def __init__(self):
        self.sequence = 0
 
    def handler(self, result):
        self.sequence += 1
        print('[{}] Got: {}'.format(self.sequence, result))
 
def apply_async(func, args, *, callback):
    # Compute the result
    result = func(*args)
 
    # Invoke the callback with the result
    callback(result)
    return 'ok'
 
 
def add(x, y):
    return x + y
 
if __name__ == '__main__':
    r = ResultHandler()
    res = apply_async(add, (2, 3), callback=r.handler)
    res = apply_async(add, ('hello', 'world'), callback=r.handler)

  

 

 

 第二种方式,作为类的替代,可以使用一个闭包捕获状态值,例如:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 异步回调
def make_handler():
    sequence = 0
    def handler(result):
        nonlocal sequence
        sequence += 1
        print('[{}] Got: {}'.format(sequence, result))
    return handler
 
def apply_async(func, args, *, callback):
    # Compute the result
    result = func(*args)
 
    # Invoke the callback with the result
    callback(result)
    return 'ok'
 
 
def add(x, y):
    return x + y
 
if __name__ == '__main__':
    handler = make_handler()
    res = apply_async(add, (2, 3), callback=handler)
    res = apply_async(add, ('hello', 'world'), callback=handler)

  

 

 

 还有另外一个更高级的方法,可以使用协程来完成同样的事情

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 异步回调
def make_handler():
    sequence = 0
    while True:
        result = yield
        sequence += 1
        print('[{}] Got: {}'.format(sequence, result))
 
def apply_async(func, args, *, callback):
    # Compute the result
    result = func(*args)
 
    # Invoke the callback with the result
    callback(result)
    return 'ok'
 
 
def add(x, y):
    return x + y
 
if __name__ == '__main__':
    handler = make_handler()
    next(handler)
    res = apply_async(add, (2, 3), callback=handler.send)
    res = apply_async(add, ('hello', 'world'), callback=handler.send)

  

 

 

posted @   Crazymagic  阅读(388)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示

目录导航