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实现依赖于第一个参数来标识类型,因此很难将此功能扩展到实例方法。
singledispatch
有人对如何使用(或使用jerry-rig)此功能使其与实例方法一起使用有任何建议吗?
更新: 从Python 3.8开始,functools.singledispatchmethod允许对方法,类方法,抽象方法和静态方法进行单次调度。 对于较旧的Python版本,请参见此答案的其余部分。
更新: 从Python 3.8开始,functools.singledispatchmethod允许对方法,类方法,抽象方法和静态方法进行单次调度。
functools.singledispatchmethod
对于较旧的Python版本,请参见此答案的其余部分。
纵观来源的singledispatch,我们可以看到,装饰返回一个函数wrapper(),它选择的功能,从那些基于类型免费通话args[0]…
wrapper()
args[0]
def wrapper(*args, **kw): return dispatch(args[0].__class__)(*args, **kw)
…对于常规函数来说很好,但是对于实例方法来说用的很少,实例方法的第一个参数始终是self。
self
但是,我们可以编写一个新的decorator methdispatch,它依赖于singledispatch执行繁重的工作,而是返回一个包装器函数,该函数根据以下类型选择要调用的注册函数args[1]:
methdispatch
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照常具有初始参数。
get()
list
测试Patchwork课程:
Patchwork
>>> pw = Patchwork(a=1, b=2, c=3) >>> pw.get("b") 2 >>> pw.get(["a", "c"]) [1, 3]