Python 里的「单分派泛函数」究竟是什么?

泛型,若是你学过Java ,应该对它不陌生吧。但你可能不知道在 Python 中(3.4+ ),也能够实现简单的泛型函数。python

在Python中只能实现基于单个(第一个)参数的数据类型来选择具体的实现方式,官方名称 是 single-dispatch。你或许听不懂,说简单点,就是能够实现第一个参数的数据类型不一样,其调用的函数也就不一样。app

singledispatch 是 PEP443 中引入的,若是你对此有兴趣,PEP443 应该是最好的学习文档:函数

https://www.python.org/dev/peps/pep-0443/学习

A generic function is composed of multiple functions implementing the same operation for different types. Which implementation should be used during a call is determined by the dispatch algorithm. When the implementation is chosen based on the type of a single argument, this is known as single dispatch.this

它使用方法极其简单,只要被singledispatch 装饰的函数,就是一个单分派的(single-dispatch )的泛函数(generic functions)。编码

单分派:根据一个参数的类型,以不一样方式执行相同的操做的行为。spa

多分派:可根据多个参数的类型选择专门的函数的行为。code

泛函数:多个函数绑在一块儿组合成一个泛函数。orm

这边举个简单的例子,介绍一下使用方法three

from functools import singledispatch

@singledispatch
def age(obj):
    print('请传入合法类型的参数!')

@age.register(int)
def _(age):
    print('我已经{}岁了。'.format(age))

@age.register(str)
def _(age):
    print('I am {} years old.'.format(age))


age(23)  # int
age('twenty three')  # str
age(['23'])  # list

执行结果

我已经23岁了。
I am twenty three years old.
请传入合法类型的参数!

提及泛型,其实在 Python 自己的一些内建函数中并很多见,好比 len()iter()copy.copy()pprint()

你可能会问,它有什么用呢?实际上真没什么用,你不用它或者不认识它也彻底不影响你编码。

我这里举个例子,你能够感觉一下。

你们都知道,Python 中有许许多的数据类型,好比 str,list, dict, tuple 等,不一样数据类型的拼接方式各不相同,因此我这里我写了一个通用的函数,能够根据对应的数据类型对选择对应的拼接方式拼接,并且不一样数据类型我还应该提示没法拼接。如下是简单的实现。

def check_type(func):
    def wrapper(*args):
        arg1, arg2 = args[:2]
        if type(arg1) != type(arg2):
            return '【错误】:参数类型不一样,没法拼接!!'
        return func(*args)
    return wrapper


@singledispatch
def add(obj, new_obj):
    raise TypeError

@add.register(str)
@check_type
def _(obj, new_obj):
    obj += new_obj
    return obj


@add.register(list)
@check_type
def _(obj, new_obj):
    obj.extend(new_obj)
    return obj

@add.register(dict)
@check_type
def _(obj, new_obj):
    obj.update(new_obj)
    return obj

@add.register(tuple)
@check_type
def _(obj, new_obj):
    return (*obj, *new_obj)

print(add('hello',', world'))
print(add([1,2,3], [4,5,6]))
print(add({'name': 'wangbm'}, {'age':25}))
print(add(('apple', 'huawei'), ('vivo', 'oppo')))

# list 和 字符串 没法拼接
print(add([1,2,3], '4,5,6'))

输出结果以下

hello, world
[1, 2, 3, 4, 5, 6]
{'name': 'wangbm', 'age': 25}
('apple', 'huawei', 'vivo', 'oppo')
【错误】:参数类型不一样,没法拼接!!

若是不使用singledispatch 的话,你可能会写出这样的代码。

def check_type(func):
    def wrapper(*args):
        arg1, arg2 = args[:2]
        if type(arg1) != type(arg2):
            return '【错误】:参数类型不一样,没法拼接!!'
        return func(*args)
    return wrapper

@check_type
def add(obj, new_obj):
    if isinstance(obj, str) :
        obj += new_obj
        return obj

    if isinstance(obj, list) :
        obj.extend(new_obj)
        return obj

    if isinstance(obj, dict) :
        obj.update(new_obj)
        return obj

    if isinstance(obj, tuple) :
        return (*obj, *new_obj)

print(add('hello',', world'))
print(add([1,2,3], [4,5,6]))
print(add({'name': 'wangbm'}, {'age':25}))
print(add(('apple', 'huawei'), ('vivo', 'oppo')))

# list 和 字符串 没法拼接
print(add([1,2,3], '4,5,6'))

输出以下

hello, world
[1, 2, 3, 4, 5, 6]
{'name': 'wangbm', 'age': 25}
('apple', 'huawei', 'vivo', 'oppo')
【错误】:参数类型不一样,没法拼接!!

以上是我我的的一些理解,若有误解误传,还请你后台留言帮忙指正!


关注公众号,获取最新干货!

相关文章
相关标签/搜索