从 API 实例化类时,我需要提供回调。如何将实例本身急切地绑定到回调?

2023-12-11

我现在在几个不同的主要第三方库和框架中都遇到了这个问题。让我尝试将其归结为要点:

  • API提供了一个类Example,构造函数期望一个callback范围。当某些事件发生时(由于我无法控制的复杂逻辑),API 将调用callback功能。
  • 我有一个函数modify接受一个实例Example并调用其上的各种方法:
    def modify(it):
        it.enabled = True
        it.visible = True
        try:
             it.paint('black')
        except AProblemComesAlong:
             it.whip()
    
  • 我想创建一个实例x of Example。当发生与以下相关的事件时x, the x实例应该通过修改modify.

因此,我想绑定x作为一个论点modify, per Python 参数绑定器。问题是,它还不存在,因为我仍在调用构造函数:

>>> from functools import partial
>>> x = Example(callback=partial(modify, x))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined

当然,我可以避免NameError通过允许lambda稍后查找名称:

>>> x = Example(callback=lambda: modify(x))

但是这个是后期绑定,所以它不能正常工作,如果例如我陷入了循环并且instance是迭代变量, or if instance稍后因任何其他原因重新分配。

我怎样才能完成早期绑定instance到它自己的回调?


一般来说,您可以尝试以下任何一种方法:

  • 仔细检查 API 是否允许您稍后设置回调(两阶段构造):
    from functools import partial
    instance = Example()
    # Read the documentation and see if Example provides something like:
    instance.callback = partial(modify, instance)
    # or possibly they didn't think of using a decorator for their validation logic:
    instance.set_callback(partial(modify, instance))
    
  • 对该示例进行子类化,以便它从自己的方法调用回调,并调整构造参数以将该方法用作包装器:
    from functools import partial
    
    class ContextProvidingExample(Example):
        def __init__(self, *args, **kwargs):
            try:
                my_callback = kwargs['callback']
                kwargs['callback'] = partial(my_callback, self)
            except KeyError:
                pass
            super().__init__(*args, **kwargs)
    
    这个想法归功于@tdelaneyhere.
  • 如果不需要灵活性,modify逻辑可以直接集成到子类中:
    class SelfModifyingExample(Example):
        def __init__(self, *args, **kwargs):
            if 'callback' in kwargs.keys():
                raise ValueError('cannot override callback')
            kwargs['callback'] = self._modify
            super().__init__(*args, **kwargs)
        def _modify(self):
            self.enabled = True
            self.visible = True
            try:
                self.paint('black')
            except AProblemComesAlong:
                self.whip()
    
  • 作为最后的手段,在字典中注册实例,并安排回调按名称查找它们:
    from functools import partial
    
    hey_you = {} # say my name...
    def modify_by_name(name):
        modify(hey_you[name]) # call modify() maybe?
    # Let's use a simple wrapper to make sure instances get registered.
    def stand_up(name):
        result = Example(callback=partial(modify_by_name, name))
        hey_you[name] = result
        return result
    
    who = what = stand_up('slim shady')
    
    这种方式有点笨拙,但您可能会发现实例的字符串名称在代码的其他地方很有用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从 API 实例化类时,我需要提供回调。如何将实例本身急切地绑定到回调? 的相关文章

随机推荐