如何将functools.singledispatch与实例方法一起使用? [英] How can I use functools.singledispatch with instance methods?

查看:127
本文介绍了如何将functools.singledispatch与实例方法一起使用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python 3.4 添加了使用静态方法定义函数重载的功能.本质上,这是文档中的示例:

Python 3.4 added the ability to define function overloading with static methods. This is essentially the example from the documentation:

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实现依赖于第一个参数来标识类型,因此很难将此功能扩展到实例方法.

In its purest form, the singledispatch implementation relies on the first argument to identify type, therefore making it tricky to extend this functionality to instance methods.

有人对如何使用(或使用jerry-rig)此功能使其与实例方法一起使用有任何建议吗?

Does anyone have any advice for how to use (or jerry-rig) this functionality to get it to work with instance methods?

推荐答案

更新:从Python 3.8开始, functools.singledispatchmethod 允许对方法,类方法,抽象方法, 和静态方法.

Update: As of Python 3.8, functools.singledispatchmethod allows single dispatch on methods, classmethods, abstractmethods, and staticmethods.

对于较旧的Python版本,请参见此答案的其余部分.

For older Python versions, see the rest of this answer.

中查找,我们可以看到装饰器返回了函数wrapper(),该函数根据args[0] ...

Looking at the source for singledispatch, we can see that the decorator returns a function wrapper(), which selects a function to call from those registered based on the type of args[0] ...

    def wrapper(*args, **kw):
        return dispatch(args[0].__class__)(*args, **kw)

...对于常规函数来说很好,但对于实例方法来说用处不大,实例方法的第一个参数始终是self.

... which is fine for a regular function, but not much use for an instance method, whose first argument is always going to be self.

但是,我们可以编写一个新的装饰器methdispatch,该装饰器依靠singledispatch进行繁重的工作,但返回一个包装器函数,该包装器函数根据args[1]的类型选择要调用的注册函数:

We can, however, write a new decorator methdispatch, which relies on singledispatch to do the heavy lifting, but instead returns a wrapper function that selects which registered function to call based on the type of 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

这是装饰器使用中的一个简单示例:

Here's a simple example of the decorator in use:

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参数.

Notice that both the decorated get() method and the method registered to list have an initial self argument as usual.

测试Patchwork类:

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

这篇关于如何将functools.singledispatch与实例方法一起使用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆