如何在实例方法中使用functools.singledispatch?
Python
3.4添加了使用静态方法定义函数重载的功能。本质上是文档中的示例:
from functools import singledispatch
class TestClass(object):
@singledispatch
def test_method(arg, verbose=False):
if verbose:
print("Let me just say,", end=" ")
print(arg)
@test_method.register(int)
def _(arg):
print("Strength in numbers, eh?", end=" ")
print(arg)
@test_method.register(list)
def _(arg):
print("Enumerate this:")
for i, elem in enumerate(arg):
print(i, elem)
if __name__ == '__main__':
TestClass.test_method(55555)
TestClass.test_method([33, 22, 11])
在最纯粹的形式上,singledispatch
实现依赖于第一个参数来标识类型,因此很难将此功能扩展到实例方法。
有人对如何使用(或使用jerry-rig)此功能使其与实例方法一起使用有任何建议吗?
-
更新: 从Python
3.8开始,functools.singledispatchmethod
允许对方法,类方法,抽象方法和静态方法进行单次调度。对于较旧的Python版本,请参见此答案的其余部分。
纵观来源的
singledispatch
,我们可以看到,装饰返回一个函数wrapper()
,它选择的功能,从那些基于类型免费通话args[0]
…def wrapper(*args, **kw): return dispatch(args[0].__class__)(*args, **kw)
…对于常规函数来说很好,但是对于实例方法来说用的很少,实例方法的第一个参数始终是
self
。但是,我们可以编写一个新的decorator
methdispatch
,它依赖于singledispatch
执行繁重的工作,而是返回一个包装器函数,该函数根据以下类型选择要调用的注册函数args[1]
:from functools import singledispatch, update_wrapper def methdispatch(func): dispatcher = singledispatch(func) def wrapper(*args, **kw): return dispatcher.dispatch(args[1].__class__)(*args, **kw) wrapper.register = dispatcher.register update_wrapper(wrapper, func) return wrapper
这是使用的装饰器的一个简单示例:
class Patchwork(object): def __init__(self, **kwargs): for k, v in kwargs.items(): setattr(self, k, v) @methdispatch def get(self, arg): return getattr(self, arg, None) @get.register(list) def _(self, arg): return [self.get(x) for x in arg]
请注意,修饰的
get()
方法和注册的方法list
都self
照常具有初始参数。测试
Patchwork
课程:>>> pw = Patchwork(a=1, b=2, c=3) >>> pw.get("b") 2 >>> pw.get(["a", "c"]) [1, 3]