使用“方法”设计回调;超载“;用Python
我设计了一个验证API,其中回调用于检查值。回调签名有两种变体:使用“方法”设计回调;超载“;用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
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的示例