单泛函数装饰器 @singledispatch

2021年1月4日 / 21次阅读 / Last Modified 2021年1月4日
装饰器

python functools模块中提供了一个函数装饰器 @ singledispatch,可以用来实现单泛函数,所谓单泛,就是指只对函数第1个参数进行泛型化处理,非第1个参数的不同类型会被直接忽略,自己处理。

虽然像python这样的动态无类型语言,泛型这样的概念是天生内嵌在其设计理念中的,但python标准团队,还是搞出来这么个装饰器。个人认为,它能够在一定程度上起到优化代码可读性的作用,单作用不大。anyway,我们来学习一下它的用法,自己不用,也许在别人的代码中能够读到呢。。

老规矩吧,直接上代码:

$ cat sdis.py
from functools import singledispatch

@singledispatch
def connect(address):
    print(address)

@connect.register
def _(addr: str):
    ip, port = addr.split(':')
    print(f'IP:{ip}, port:{port}')

@connect.register
def _(addr: tuple):
    ip, port = addr
    print(f'IP:{ip}, port:{port}')

connect('123.45.67.18:12345')
connect(('123.45.32.18', 23456))
connect(567)

用 @singledispatch 装饰主函数connect,主函数很简单,直接打印入参。然后用衍生的 @connect.register 装饰主函数不同入参类型的版本。上面代码写法,使用的是typing hint的方式,从python3.7开始有。

执行时,3次调用connect,分别传输str,tuple和int,执行效果如下:

$ python3 sdis.py
IP:123.45.67.18, port:12345
IP:123.45.32.18, port:23456
567

经过 @singledispatch 装饰后,在调用connect函数时,最终调用的哪个函数就非常清楚,一目了然了!dispatch的依据,就是函数定义时的type类型。

@singledispatch是从python3.4开始的,因此还有一种写法:

t$ cat sdis.py
from functools import singledispatch


@singledispatch
def connect(address):
    print(address)

@connect.register(str)
def _(addr):
    ip, port = addr.split(':')
    print(f'IP:{ip}, port:{port}')

@connect.register(tuple)
def _(addr):
    ip, port = addr
    print(f'IP:{ip}, port:{port}')


connect('123.45.67.18:12345')
connect(('123.45.32.18', 23456))
connect(567)

在衍生出来的register装饰器后面带上第1个参数的类型,这种写法,感觉似乎更亲切(其实是还完全不同typing hints的用意)。

最后说一下多参数的情况:python提供的这种单泛型机制,可以实现不同类型的第1个参数时,函数参数个数的不同。用这个机制,连参数的默认值都不需要,直接是相同函数名,因第1个参数的类型,而带来的参数个数的不同!

$ cat sdis.py
from functools import singledispatch


@singledispatch
def connect(address, info=''):
    print(address)
    print(info)

@connect.register(str)
def _(addr, a, b, c):
    ip, port = addr.split(':')
    print(f'IP:{ip}, port:{port}')
    print(a,b,c)

@connect.register(tuple)
def _(addr):
    ip, port = addr
    print(f'IP:{ip}, port:{port}')


connect('123.45.67.18:12345', 1,2,3)
connect(('123.45.32.18', 23456))
connect(567, 'original')

主函数connect可以接收2个参数,而str类型时,接收4个参数,都没有默认值,tuple类型时,就只有1个参数。python真的TTMD灵活了......

以上代码运行效果如下:

$ python3 sdis.py
IP:123.45.67.18, port:12345
1 2 3
IP:123.45.32.18, port:23456
567
original

虽然python是动态语言,有鸭子类型,但标准团队提供的 @singledispatch 还是有价值的,用好了,对代码的可读性和可维护性都有提高!

-- EOF --

本文链接:https://www.pynote.net/archives/3076

留言区

邮箱地址不会被公开。 必填项已用*标注


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top