如何在实例方法中使用functools.singledispatch?

发布于 2021-01-29 19:21:29

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)此功能使其与实例方法一起使用有任何建议吗?

关注者
0
被浏览
53
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    更新: 从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()方法和注册的方法listself照常具有初始参数。

    测试Patchwork课程:

    >>> pw = Patchwork(a=1, b=2, c=3)
    >>> pw.get("b")
    2
    >>> pw.get(["a", "c"])
    [1, 3]
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看