You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 06:06:25