在Python中用重载方法设计回调

2024-10-03 23:19:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我设计了一个验证API,其中回调用于检查值。回调签名有两种变体:

def check(self, value):
    pass

def check(self, value, domain_object):          
    pass

调用回调实现的示例:

^{pr2}$

现在,我在调用方法之前反射性地计算参数的数量,并根据结果向其传递一个或两个参数。但是这种款式好吗?在

会更好吗

  • 始终使用带有三个参数的签名:check(self, value, domain_object)
  • 对第二种情况使用不同的名称,如check_with_domain_object?在

我认为在oop方面,始终使用三参数变量是最干净的方法。你怎么认为?在


Tags: 方法selfapi示例参数数量objectvalue
3条回答

我喜欢@Space_C0wb0y的答案,它类似于raymondhettinger发送给我的代码,用于解决pyparsing中类似的情况(见下文)。对于您的简单示例,请尝试使用以下normalizer类包装给定的回调:

class _ArityNormalizer(object):
    def __init__(self, fn):
        self.baseFn = fn
        self.wrapper = None

    def __call__(self, value, domain_object):
        if self.wrapper is None:
            try:
                self.wrapper = self.baseFn
                return self.baseFn(value, domain_object)
            except TypeError:
                self.wrapper = lambda v,d: self.baseFn(v)
                return self.baseFn(value)
        else:
            return self.wrapper(value, domain_object)

您的代码现在可以将回调包装在_ArityNormalizer中,并且在回调时,总是使用2个参数进行调用。_ArityNormalizer只执行一次尝试错误的“使用2个参数调用,如果失败,则使用1个参数调用”逻辑,此后将直接转到正确的形式。在

在pyparsing中,我希望支持可能被定义为接受0、1、2或3个参数的回调,并编写代码,根据回调函数的签名,用几个修饰符之一包装被调用函数。这样,在运行/回调时,我总是用3个参数进行调用,而装饰器负责使用正确数量的参数进行实际调用。在

我的代码做了很多脆弱的/不可移植的/版本敏感的签名自省来完成这项工作(听起来像是操作目前正在做的),直到raymondhettinger给我一个很好的arity裁剪方法,它基本上实现了@Space_C0wb0y的答案所建议的。RH的代码使用了一些非常简洁的修饰符来包装一个非局部变量来记录成功调用的arity,因此您只需经历一次尝试和错误,而不是每次调用回调。您可以在SourceForge上的pyparsing SVN存储库中的函数_trim_arity中看到他的代码—注意,由于使用了“nonlocal”关键字,他的代码有Py2/Py3变体。在

上面的_ArityNormalizer代码的灵感来自RH的代码,在我完全理解他的代码的魔力之前。在

“Space_C0wb0y”使用try ... except TypError的想法看起来不错,但我不喜欢这样做会吞并其他异常paulmcguire“对_ArityNormalizer的建议本质上与一个好的接口是一样的。在

最后,我决定让事情尽可能简单和面向对象,并始终使用两个参数,即使在某些情况下第二个参数将不被使用:

实施方:

def check(self, value, domain_object):          
    pass

主叫方:

^{pr2}$

最惯用的方法是先尝试两个参数,如果失败,则使用一个:

try:
    callback(value_param, domain_object_param)
except TypeError:
    callback(value_param)

相关问题 更多 >