Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/279.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用“方法”设计回调;超载“;用Python_Python_Oop_Callback_Overloading - Fatal编程技术网

使用“方法”设计回调;超载“;用Python

使用“方法”设计回调;超载“;用Python,python,oop,callback,overloading,Python,Oop,Callback,Overloading,我设计了一个验证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) depen

我设计了一个验证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\u object)
  • 对于第二种情况,请使用另一个名称,如
    check\u with\u domain\u object

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

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

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

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

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

我喜欢@Space_c0w0y的答案,它类似于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)
您的代码现在可以将回调封装在一个
\u ArityNormalizer
中,并且在回调时,始终使用两个参数进行调用
\u ArityNormalizer
将只执行一次试错“使用2个参数调用,如果失败,则使用1个参数调用”逻辑,然后将直接转到正确的形式

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

我的代码为此做了很多脆弱的/不可移植的/版本敏感的签名内省(听起来像OP目前正在做的),直到Raymond Hettinger给我发送了一个很好的算术修剪方法,基本上实现了@Space_C0wb0y的答案所建议的。RH的代码使用了一些非常简洁的装饰程序,并使用了一个非局部变量来记录成功调用的算术性,因此您只需经历一次尝试和错误,而不是每次调用回调。您可以在SourceForge上的pyparsing SVN存储库中的函数
\u trim\u arity
中看到他的代码-注意,由于使用了“nonlocal”关键字,他的代码有Py2/Py3变体


上面的
\u ArityNormalizer
代码是从RH的代码中获得灵感的,在我完全理解他的代码的魔力之前。

我喜欢@Space\u 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)
您的代码现在可以将回调封装在一个
\u ArityNormalizer
中,并且在回调时,始终使用两个参数进行调用
\u ArityNormalizer
将只执行一次试错“使用2个参数调用,如果失败,则使用1个参数调用”逻辑,然后将直接转到正确的形式

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

我的代码为此做了很多脆弱的/不可移植的/版本敏感的签名内省(听起来像OP目前正在做的),直到Raymond Hettinger给我发送了一个很好的算术修剪方法,基本上实现了@Space_C0wb0y的答案所建议的。RH的代码使用了一些非常简洁的装饰程序,并使用了一个非局部变量来记录成功调用的算术性,因此您只需经历一次尝试和错误,而不是每次调用回调。您可以在SourceForge上的pyparsing SVN存储库中的函数
\u trim\u arity
中看到他的代码-注意,由于使用了“nonlocal”关键字,他的代码有Py2/Py3变体

上面的
\u ArityNormalizer
代码是受RH代码的启发,在我完全理解他的代码的魔力之前。

“Space\u c0w0y”的想法是使用
试试。。。除了TypeError(类型错误)
看起来不错,但我不喜欢这会吞噬其他异常的事实。“Paul McGuire”对
\u ArityNormalizer
的建议本质上与漂亮的界面相同

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

执行方:

def check(self, value, domain_object):          
    pass
主叫方:

constraint.check(value, domain_object)
“Space_C0wb0y”的想法是使用
试试。。。除了TypeError(类型错误)
看起来不错,但我不喜欢这会吞噬其他异常的事实。“Paul McGuire”对
\u ArityNormalizer
的建议本质上与漂亮的界面相同

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

执行方:

def check(self, value, domain_object):          
    pass
主叫方:

constraint.check(value, domain_object)

您不能为
域对象
指定一些默认值吗?。。。默认值,*args/**kws,唯一方法名称。。。视情况而定。保持简单。这就是“Python方式”,对吗?;-)也许您可以添加一个函数如何使用的示例,以澄清问题。@Evpok我的意图是在实现端完全避免使用
domain\u对象
param,如果不需要的话。@Space\u C0wb0y:我添加了一个调用callb的示例