Python 的弱引用和回调函数
回调函数
回调函数(Callback Function) 是一种编程模式,指的是将一个函数作为参数传递给另一个函数,并在特定时机(如事件触发、异步操作完成、条件满足等)被调用执行。
实现异步操作(如网络请求、文件读写完成后的处理)
实现事件驱动(如 GUI 中按钮点击、定时器触发)
提高代码灵活性和复用性(不同场景传入不同回调函数)
优点:
灵活性高:行为可动态配置
解耦:调用者和被调用者无需直接依赖
适合事件/异步模型
缺点:
回调地狱(Callback Hell):多层嵌套回调导致代码难以阅读和维护
错误处理复杂:异常传播困难
调试困难:调用栈不直观
实现方式
-
基础回调
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 需要回调的函数
def greet(name):
print(f"Hello, {name}!")
# 主函数,将回调函数作为参数
def process_user(name, callback):
print("Processing user...")
callback(name) # 回调!
# 调用主函数
process_user("Alice", greet)
# 输出:
# Processing user...
# Hello, Alice! -
带返回值的回调
1
2
3
4
5
6
7
8
9
10def square(x):
return x * x
# 调用回调函数计算
def apply_operation(numbers, operation):
return [operation(num) for num in numbers]
# 输出结果
result = apply_operation([1, 2, 3, 4], square)
print(result) # [1, 4, 9, 16] -
匿名函数(lambda)的回调
1
2
3numbers = [1, 2, 3, 4, 5]
result = list(map(lambda x: x ** 2, numbers))
print(result) # [1, 4, 9, 16, 25] -
事件驱动回调
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
26
27class Button:
def __init__(self):
self.click_callbacks = []
def on_click(self, callback):
self.click_callbacks.append(callback)
def click(self):
print("Button clicked!")
for callback in self.click_callbacks:
callback()
def say_hello():
print("Hello from callback!")
def log_click():
print("Button was clicked at some time.")
btn = Button()
btn.on_click(say_hello)
btn.on_click(log_click)
btn.click()
# 输出:
# Button clicked!
# Hello from callback!
# Button was clicked at some time.
异步回调
-
使用 threading 的异步回调
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18import threading
import time
def async_task(callback):
def worker():
time.sleep(2) # 模拟耗时操作
result = "Task completed!"
callback(result)
# 异步执行
thread = threading.Thread(target=worker)
thread.start()
# 回调函数
def handle_result(result):
print(f"Received result: {result}")
print("Starting async task...")
async_task(handle_result) -
回调 + 参数绑定(functools)
回调函数需要额外参数,但调用方只允许传入无参函数
1
2
3
4
5
6
7
8
9
10from functools import partial
def notify_user(user_id, message):
print(f"User {user_id}: {message}")
# 绑定部分参数
callback = partial(notify_user, 123, "Your task is done!")
# 模拟触发
callback() # 输出: User 123: Your task is done!
弱引用
弱引用(Weak Reference) 是一种特殊的引用方式,它不会增加对象的引用计数,因此不会阻止对象被垃圾回收机制回收。
Python 使用引用计数作为主要的垃圾回收机制。当一个对象的引用计数变为 0 时,它就会被自动回收。
但在某些场景下,我们希望“观察”或“缓存”一个对象,但又不希望因为我们的引用而阻止它被回收 —— 这就是弱引用的用武之地。
-
强引用(Strong Reference):普通的变量赋值、容器存储等,会增加引用计数。
-
弱引用(Weak Reference):不会增加引用计数,对象可被正常回收。
-
弱引用指向的对象一旦被回收,弱引用会自动失效(变成
None或抛出异常)。
不是所有对象都支持弱引用!只有支持弱引用协议的对象才可以。
支持弱引用的对象:
用户自定义类的实例(默认支持)
部分内置类型(如
list,dict在某些 Python 版本中支持,但不推荐依赖)
不支持弱引用的对象:
int,str,tuple,float等不可变内置类型(出于性能和实现原因)部分 C 扩展对象
使用 weakref
Python 提供了标准库 weakref 来创建和管理弱引用。
1 | import weakref |
带回调的弱引用
可以在对象被回收时触发一个回调函数:
1 | import weakref |
弱引用字典
-
WeakKeyDictionary:键是弱引用(键可被回收)
1 | import weakref |
-
WeakValueDictionary:值是弱引用(值可被回收)键或值必须是可哈希对象(通常是自定义类实例),不能是
list,dict等不可哈希类型。1
2
3
4
5
6
7
8
9
10
11weak_val_dict = weakref.WeakValueDictionary()
obj1 = MyClass("Obj1")
obj2 = MyClass("Obj2")
weak_val_dict["a"] = obj1
weak_val_dict["b"] = obj2
print("当前字典:", dict(weak_val_dict))
del obj1
print("删除 obj1 后:", dict(weak_val_dict)) # 只剩 'b': obj2
弱引用集合
类似 set,但元素是弱引用:
1 | weak_set = weakref.WeakSet() |
应用场景
-
缓存系统,避免内存泄漏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import weakref
class DataCache:
def __init__(self):
self._cache = weakref.WeakValueDictionary()
def get(self, key):
return self._cache.get(key)
def set(self, key, value):
self._cache[key] = value
cache = DataCache()
big_data = MyClass("BigData")
cache.set("data1", big_data)
print(cache.get("data1")) # 存在
del big_data
print(cache.get("data1")) # None —— 自动清理! -
观察者模式 / 事件监听器,避免循环引用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class Subject:
def __init__(self):
self._observers = weakref.WeakSet()
def add_observer(self, observer):
self._observers.add(observer)
def notify(self):
for obs in self._observers:
obs.update()
class Observer:
def update(self):
print("收到通知!")
subject = Subject()
observer = Observer()
subject.add_observer(observer)
subject.notify() # 收到通知!
del observer # observer 被回收,自动从 WeakSet 中移除
subject.notify() # 无输出,不会报错 -
父子对象引用,避免循环引用导致内存泄漏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18class Parent:
def __init__(self, name):
self.name = name
self.children = []
class Child:
def __init__(self, name, parent):
self.name = name
self.parent = weakref.ref(parent) # 弱引用父对象,避免循环引用
p = Parent("Parent1")
c = Child("Child1", p)
p.children.append(c)
print(c.parent().name) # Parent1
del p # 父对象可被正常回收
print(c.parent()) # None
系统中的应用
支持传递多个参数+弱引用的回调函数使用
定义回调函数
支持多个参数:用于处理主函数完成后的操作:成功或失败的处理
1 | def handle_workflow_completion(self, task_id, prompt_id, success, msg, **kwargs): |
定义主函数
主函数内部可以继续使用回调函数:on_complete、on_error
1 | def async_run_workflow(self, on_complete=None, on_error=None, task_id=None): |
定义执行函数
执行主函数,调用回调函数
1 | def check_workflow_status_async(self, prompt_id: str, |
弱引用调用回调函数
使用 functools 包装所有参数,使用 weakref 调用 functools
1 | def callback_with_complete(self, task_id: str, prompt_id: str, success: bool, msg: str, on_complete): |
