繁体   English   中英

使用Python中的方法“重载”设计回调

[英]Designing callbacks with method “overloading” in Python

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

def check(self, value):
    pass

def check(self, value, domain_object):          
    pass

调用回调实现的示例:

for constraint in constraints:
    constraint.check(value) 
    # or constraint.check(value, domain_object) depending on the implementation

现在我在调用方法之前反复计算参数的数量,并根据结果向其传递一两个参数。 但这是好风格吗?

它会更好吗?

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

我认为就oop来说,这将是总是使用三个参数变体的最干净的方法。 你怎么看?

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

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

我喜欢@ Space_C0wb0y的答案,它类似于代码Raymond Hettinger发送给我来解决类似情况的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个args调用,如果失败则调用1个arg”逻辑只执行一次,从那时起将直接转到正确的形式。

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

我的代码做了很多脆弱/非便携/版本敏感的签名内省来做到这一点(听起来就像OP目前正在做的那样),直到Raymond Hettinger给我发送了一个很好的arity-trimming方法,基本上解决了@Space_C0wb0y的答案。 RH的代码使用一些非常整洁的装饰器包装和非局部变量来记录成功调用的arity,这样你只需要经历一次试错,而不是每次调用回调。 您可以在函数_trim_arity中的SourceForge上的pyparsing SVN存储库中查看他的代码 - 请注意,由于使用了“nonlocal”关键字,他的代码具有Py2 / Py3变体。

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

“Space_C0wb0y”的想法是使用try ... except TypError看起来不错,但我不喜欢这可以吞下其他异常的事实。 “Paul McGuire”对_ArityNormalizer的建议基本上与一个漂亮的界面相同。

最后,我决定保持尽可能简单和面向对象的东西,并且总是有两个参数,即使有几个情况下第二个参数将被使用:

实施方:

def check(self, value, domain_object):          
    pass

呼叫方:

constraint.check(value, domain_object)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM