python functools.singledispatch 装饰器实现类似重载的功能

大家知道 Python 不支持重载方法或函数,因此有不定参数*args, **kwargs,但是对于使用不同的方式处理不同的数据类型情况,我们一般要使用 if/elif/elif 将函数变成一个分派函数,这样不便于模块的用户扩展,还显得笨拙:时间一长,分派函数 会变得很大,而且它与各个专门函数之间的耦合也很紧密。

Python 3.4 新增的 functools.singledispatch 装饰器可以把整体方案拆分成多个模块,甚至可以为你无法修改的类提供专门的函数。使用 @singledispatch 装饰的普通函数会变成 泛函数generic function):根据第一个参数的类型,以不同方式执行相同操作的一组函数

例如:

"""
使用 singledispatch 装饰器实现类似函数的重载功能
"""
from functools import singledispatch
from collections import abc
import numbers
import html


#  @singledispatch 标记处理 object 类型的基函数
@singledispatch
def htmlize(obj):
    content = html.escape(repr(obj))
    return '<pre>{}</pre>'.format(content)


# 各个专门函数使用 @«base_function».register(«type») 装饰
# 专门函数的名称无关紧要;_ 是个不错的选择,简单明了。
@htmlize.register(str)
def _(text):
    content = html.escape(text).replace('\n', '<br>\n')
    return '<p>{0}</p>'.format(content)


# 为每个需要特殊处理的类型注册一个函数。numbers.Integral 是 int 的虚拟超类。
@htmlize.register(numbers.Integral)
def _(n):
    return '<pre>{0} (0x{0:x})</pre>'.format(n)


# 可以叠放多个 register 装饰器,让同一个函数支持不同类型
@htmlize.register(tuple)
@htmlize.register(abc.MutableSequence)
def _(seq):
    inner = '</li>\n<li>'.join(htmlize(item) for item in seq)
    return '<ul>\n<li>' + inner + '</li>\n</ul>'


if __name__ == "__main__":
    print(htmlize('123'))
    print(htmlize((1, 3, 5)))

执行结果:
在这里插入图片描述
由此 singledispatch 实现,将函数变为 泛函数 ,实现了类似重载的功能。

注意:

只要可能,注册的专门函数应该处理抽象基类(如 numbers.Integralabc.MutableSequence), 不要处理具体实现(如 intlist)。这样,代码支持的兼容类型更广泛。例如,Python 扩展可以子类化 numbers.Integral,使用固定的位数实现 int 类型。

singledispatch 机制的一个显著特征是,你可以在系统任何地方任何模块中注册专门函数。如果后来在新的模块中定义了新的类型,可以轻松地添加一个新的专门函数来处理 那个类型。此外,你还可以为不是自己编写的或者不能修改的类添加自定义函数。官方文档:(https:// www.python.org/dev/peps/pep-0443/

@singledispatch 不是为了把Java 的那种方法重载带入Python。在一个类 中为同一个方法定义多个重载变体,比在一个函数中使用一长串 if/elif/ elif/elif 块要更好。但是这两种方案都有缺陷,因为它们让代码单元(类 或函数)承担的职责太多@singledispath 的优点是支持模块化扩展:各个模块可以为它支持的各个类型注册一个专门函数

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值