说明
《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
Python 内置模块 functools 的一个高阶函数装饰器 @singledispatch 装饰器可将一个函数转换为单分派。要定义一个泛型函数,应使用 @singledispatch 装饰器进行装饰。泛型函数可以实现第一个参数的数据类型不同,其调用的函数也就不同。
请注意分派是作用于第一个参数的类型,要相应地创建你的函数,下例中对 age() 函数进行了分派,传入不同类型的值分派到不同的函数上:
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
# 我已经23岁了。
age('twenty three') # str
# I am twenty three years old.
age(['23']) # list
# 请传入合法类型的参数!
在原函数上增加装饰器 @singledispatch,然后再分支函数上增加 @fun.register(str)
之类的装饰器,在装饰器中指定传入的数据类型,并针对此类型进行处理。
单分派(single dispatch)一种泛型函数分派形式,其实现是基于单个参数的类型来选择的。泛型函数(generic function)为不同的类型实现相同操作的多个函数所组成的函数,在调用时会由调度算法来确定应该使用哪个实现。
泛型函数由多个函数组成,这些函数对不同类型执行相同的操作。调用期间应该使用哪个实现由调度算法决定。当根据单个参数的类型选择实现时,这称为单个分派。
总结:
创建你的函数:
>>> from functools import singledispatch
>>> @singledispatch
... def fun(arg, verbose=False):
... if verbose:
... print("Let me just say,", end=" ")
... print(arg)
要将重载的实现添加到函数中,请使用泛型函数的 register() 属性。 它是一个装饰器。 对于带有类型标注的函数,该装饰器将自动推断第一个参数的类型:
>>> @fun.register
... def _(arg: int, verbose=False):
... if verbose:
... print("Strength in numbers, eh?", end=" ")
... print(arg)
...
>>> @fun.register
... def _(arg: list, verbose=False):
... if verbose:
... print("Enumerate this:")
... for i, elem in enumerate(arg):
... print(i, elem)
对于不使用类型标注的代码,可以将适当的类型参数显式地传给装饰器本身:
>>> @fun.register(complex)
... def _(arg, verbose=False):
... if verbose:
... print("Better than complicated.", end=" ")
... print(arg.real, arg.imag)
要启用注册 lambda 和现有函数,可以使用函数形式的 register() 属性:
>>> def nothing(arg, verbose=False):
... print("Nothing.")
...
>>> fun.register(type(None), nothing)
register() 属性将返回启用了装饰器堆栈、封存的未装饰函数,并会为每个变量单独创建单元测试:
>>> @fun.register(float)
... @fun.register(Decimal)
... def fun_num(arg, verbose=False):
... if verbose:
... print("Half of your number:", end=" ")
... print(arg / 2)
...
>>> fun_num is fun
False
在调用时,泛型函数会根据第一个参数的类型进行分派:
>>> fun("Hello, world.")
Hello, world.
>>> fun("test.", verbose=True)
Let me just say, test.
>>> fun(42, verbose=True)
Strength in numbers, eh? 42
>>> fun(['spam', 'spam', 'eggs', 'spam'], verbose=True)
Enumerate this:
0 spam
1 spam
2 eggs
3 spam
>>> fun(None)
Nothing.
>>> fun(1.23)
0.615
在没有用于特定类型的已注册实现的情况下,则会使用其方法解析顺序来查找更通用的实现。 以 @singledispatch 装饰的原始函数将为最基本的 object 类型进行注册,这意味着它将在找不到更好的实现时被使用。
如果一个实现注册到了 abstract base class,虚拟子类将会被发送到该实现:
>>> from collections.abc import Mapping
>>> @fun.register
... def _(arg: Mapping, verbose=False):
... if verbose:
... print("Keys & Values")
... for key, value in arg.items():
... print(key, "=>", value)
...
>>> fun({"a": "b"})
a => b
要检查泛型函数将为给定类型选择哪个实现,请使用 dispatch() 属性:
>>> fun.dispatch(float)
<function fun_num at 0x1035a2840>
>>> fun.dispatch(dict) # note: default implementation
<function fun at 0x103fe0000>
要访问所有已经注册实现的函数,请使用只读的 registry 属性:
>>> fun.registry.keys()
'''
dict_keys([<class 'NoneType'>, <class 'int'>, <class 'object'>,
<class 'decimal.Decimal'>, <class 'list'>,
<class 'float'>])
'''
>>> fun.registry[float]
<function fun_num at 0x1035a2840>
>>> fun.registry[object]
<function fun at 0x103fe0000>
更新版本:
更新时间:2022-01-20 09:49:23 标签:python 装饰器 函数 单分派