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

问题描述 投票:35回答:2

Python的3.4 added的能力来定义函数的静态方法重载。这实质上是从文档的例子:

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实现依赖于第一个参数,以确定类型,因此使它棘手此功能扩展到实例方法。

有没有人有如何使用(或杰里 - 钻机)此功能让它与实例方法的工作有什么建议?

python python-3.x python-3.4 instance-method single-dispatch
2个回答
60
投票

更新:对于Python 3.8,functools.singledispatchmethod将允许在方法,classmethods,abstractmethods和staticmethods单牒。

对于老版本的Python,看到这个答案的其余部分。

纵观sourcesingledispatch,我们可以看到,装饰返回功能wrapper(),它选择的功能,从那些基于args[0]的类型注册打电话......

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

......这是罚款,一个普通的功能,而不是一个实例方法,它的第一个参数多大用处总是将是self

我们可以,但是,写一个新的装饰methdispatch,依靠q​​azxswpoi做繁重,而是返回选择哪个注册函数来调用基于singledispatch的类型的包装功能:

args[1]

下面是使用Decorator的一个简单的例子:

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

11
投票

装饰器本质上是一个包装,是以包装的函数作为参数并返回另一个功能。

作为接受的答案说,>>> pw = Patchwork(a=1, b=2, c=3) >>> pw.get("b") 2 >>> pw.get(["a", "c"]) [1, 3] 返回singledispatch,是以第一个参数是注册类型 - wrapper的实例方法。

作为这个问题的答案所示,在这样的情况下,你可以写其他包装猴子修补装饰。但这种哈克修复并不总是最好的选择。

正如像任何其他功能,您可以拨打包装,并明确地传递参数给它,这似乎更简单,扁平化,更具可读性,我如果这种方法的重载只在很少的包装制作。

self

还有另外一个模块,from functools import singledispatch class TestClass(object): def __init__(self): self.test_method = singledispatch(self.test_method) self.test_method.register(int, self._test_method_int) self.test_method.register(list, self._test_method_list) def test_method(self, arg, verbose=False): if verbose: print("Let me just say,", end=" ") print(arg) def _test_method_int(self, arg): print("Strength in numbers, eh?", end=" ") print(arg) def _test_method_list(self, arg): print("Enumerate this:") for i, elem in enumerate(arg): print(i, elem) if __name__ == '__main__': test = TestClass() test.test_method(55555) test.test_method([33, 22, 11]) (不标准,但包括在蟒蛇,没有任何非标准的依赖),作为名字已经表明,不像multipledispatch,允许多方法。

除了singledispatch对象,与Dispatcher兼容构造结,它提供了一个singledispatch装饰,其对用户隐藏这些对象的创建和操纵。

调度装饰使用函数的名称来选择合适的调度对象,它增加了新的签名/功能。当它遇到一个新的功能将其命名为创建一个新的Dispatcher对象和商店名称/调度以供将来参考命名空间对。

例如:

dispatch
© www.soinside.com 2019 - 2024. All rights reserved.