Python函数包装保留引用或动态添加位置参数的实现方法
适配pyglet调度函数参数且支持取消调度的方案
核心需求:让不带dt首位参数的函数适配pyglet的schedule_once要求,同时能正常执行取消调度操作(避免包装后的函数与原函数/方法引用不匹配的问题)。
方案一:自定义包装类(推荐,自动支持取消)
通过实现一个可调用的包装类,重写相等性判断与哈希方法,让包装实例与原函数/方法在比较时被视为同一对象,完美解决取消调度的匹配问题。
import functools # 模拟pyglet的调度系统 scheduled_functions = [] def schedule_once(func, delay, *args, **kwargs): print('scheduled func :', func) scheduled_functions.append(func) def unschedule(func): print('try to unschedule ', func) if func in scheduled_functions: scheduled_functions.remove(func) print('unscheduled successfully') else: print(func, 'not found') class DTWrapper: def __init__(self, func): self.func = func def __call__(self, dt, *args, **kwargs): # 忽略调度传入的dt参数,直接执行原函数 return self.func(*args, **kwargs) def __eq__(self, other): # 让包装实例与原函数/方法、同原函数的其他包装实例相等 if isinstance(other, DTWrapper): return self.func is other.func return self.func is other def __hash__(self): # 复用原函数的哈希值,确保在列表/集合中能被正确查找 return hash(self.func) def delay_run(delay: float, func, *args, **kwargs): if not isinstance(delay, (float, int)): return False if delay <= 0: return func(*args, **kwargs) wrapper = DTWrapper(func) schedule_once(wrapper, delay, *args, **kwargs) return wrapper # 测试绑定方法的场景 class Foo: def destroy(self): print('destroy ', self) f = Foo() delay_run(1, f.destroy) unschedule(f.destroy)
运行输出:
scheduled func : <__main__.DTWrapper object at 0x7f7f39fc9b40> try to unschedule <bound method Foo.destroy of <__main__.Foo object at 0x7f7f39fc9a80>> unscheduled successfully
方案二:lambda+手动保存引用(轻量场景)
如果仅需处理少量调度任务,可直接用lambda忽略dt参数,但必须保存lambda的引用才能执行取消操作:
delay = 1.0 def foo(arg1): print(arg1) # 创建包装lambda并保存引用 wrapper = lambda dt: foo('hello') pyglet.clock.schedule_once(wrapper, delay) # 取消调度时使用保存的引用 pyglet.clock.unschedule(wrapper)
该方式无需额外代码,但需手动管理每个包装后的引用,否则无法取消调度。
方案三:functools.partial包装(参数绑定场景)
当需要为原函数绑定固定参数时,可结合functools.partial和lambda实现:
import functools delay = 1.0 def foo(arg1): print(arg1) # 绑定固定参数到原函数 partial_func = functools.partial(foo, 'hello') # 包装成接收dt参数的函数 wrapper = lambda dt: partial_func() pyglet.clock.schedule_once(wrapper, delay) # 取消调度时使用wrapper引用 pyglet.clock.unschedule(wrapper)
同样需要保存最终的包装引用,适合需要提前绑定参数的场景。
内容的提问来源于stack exchange,提问作者Joonhyuk Choi
相关产品推荐
相关产品推荐

