python中的多重分派

plum-dispatch的Python项目详细描述


Plum: Multiple Dispatch in Python

BuildCoverage StatusLatest Docs

每个人都喜欢多发,就像每个人都喜欢李子一样。

安装

pip install plum-dispatch

基本用法

多分派允许您为同一对象实现多个方法 函数,其中方法指定其参数的类型:

fromplumimportdispatch@dispatch(str)deff(x):return'This is a string!'@dispatch(int)deff(x):return'This is an integer!'
>>>f('1')'This is a string!'>>>f(1)'This is an integer!'

我们还没有为floats实现方法,因此在这种情况下出现异常 将被提升:

>>>f(1.0)NotFoundLookupError:Forfunction"f",signature(builtins.float)couldnotberesolved.

与其为floats实现方法,不如为 所有号码:

fromnumbersimportNumber@dispatch(Number)deff(x):return'This is a number!'

由于floatNumber,因此f(1.0)将返回'This is a number!'。 但是int也是Number,因此f(1)可以返回 'This is an integer!''This is a number!'。 多重分派的规则是选择最具体的方法:

>>>f(1)'This is an integer!'

因为intNumber,但是Number不一定是int

有关多个分派的详细概述,请参见 manual of the Julia Language

按示例列出的功能

从类型注释分派

Dispatcher.annotations是一个实验特性,可以用来 对函数的类型批注进行调度:

fromplumimportdispatch,add_conversion_methodadd_conversion_method(type_from=int,type_to=str,f=str)@dispatch.annotations()defint_to_str(x:int)->str:returnx@dispatch.annotations()defint_to_str(x):raiseValueError('I only take integers!')
>>>int_to_str(1.0)ValueError:Ionlytakeintegers!>>>int_to_str(1)'1'

接头类型

集合可用于实例化联合类型:

fromplumimportdispatch@dispatch(object)deff(x):print('fallback')@dispatch({int,str})deff(x):print('int or str')
>>> f(1)
int or str

>>> f('1')
int or str

>>> f(1.0)
fallback

参数类型

参数类型TupleList可用于在元组上分派 以及包含特定类型元素的列表。 重要的是,类型系统是covariant,而不是julia的类型 系统,它是不变的

fromplumimportdispatch,Tuple,List@dispatch({tuple,list})deff(x):print('tuple or list')@dispatch(Tuple(int))deff(x):print('tuple of int')@dispatch(List(int))deff(x):print('list of int')
>>>f([1,2])'list of int'>>>f([1,'2'])'tuple or list'>>>f((1,2))'tuple of int'>>>f((1,'2'))'tuple or list'

变量参数

列表可用于指定变量参数:

fromplumimportdispatch@dispatch(int)deff(x):print('single argument')@dispatch(int,[int])deff(x,*xs):print('multiple arguments')
>>> f(1)
single argument

>>> f(1, 2)
multiple arguments

>>> f(1, 2, 3)
multiple arguments

返回类型

关键字参数return_type可以设置为指定返回类型:

fromplumimportdispatch,add_conversion_method@dispatch({int,str},return_type=int)deff(x):returnx
>>>f(1)1>>>f('1')TypeError:Expectedreturntype"builtins.int",butgottype"builtins.str".>>>add_conversion_method(type_from=str,type_to=int,f=int)>>>f('1')1

遗传

因为python中的每个类都可以被子类化,所以对角线分派不能 实施。 但是,继承可以用来实现一种对角分派:

fromplumimportDispatcher,Referentiable,SelfclassReal(Referentiable):dispatch=Dispatcher(in_class=Self)@dispatch(Self)def__add__(self,other):return'real'classRational(Real,Referentiable):dispatch=Dispatcher(in_class=Self)@dispatch(Self)def__add__(self,other):return'rational'real=Real()rational=Rational()
>>> real + real
'real'

>>> real + rational
'real'

>>> rational + real
'real'

>>> rational + rational
'rational'

转换

函数convert可用于将一种类型的对象转换为另一种类型:

fromnumbersimportNumberfromplumimportconvertclassRational(object):def__init__(self,num,denom):self.num=numself.denom=denom
>>>convert(0.5,Number)0.5>>>convert(Rational(1,2),Number)TypeError:Cannotconverta"__main__.Rational"toa"numbers.Number".

TypeError表示convert不知道如何转换 RationalNumber。 让我们实现这种转换:

fromoperatorimporttruedivfromplumimportconversion_method@conversion_method(type_from=Rational,type_to=Number)defrational_to_number(q):returntruediv(q.num,q.denom)
>>>convert(Rational(1,2),Number)0.5

除了装饰符conversion_method,还可以使用 add_conversion_method

fromplumimportadd_conversion_methodadd_conversion_method(type_from,type_to,conversion_function)

促销

函数promote可用于将对象提升为公共类型:

fromplumimportdispatch,promote,add_promotion_rule,add_conversion_method@dispatch(object,object)defadd(x,y):returnadd(*promote(x,y))@dispatch(int,int)defadd(x,y):returnx+y@dispatch(float,float)defadd(x,y):returnx+y
>>>add(1,2)3>>>add(1.0,2.0)3.0>>>add(1,2.0)TypeError:Nopromotionrulefor"builtins.int"and"builtins.float".>>>add_promotion_rule(int,float,float)>>>add(1,2.0)TypeError:Cannotconverta"builtins.int"toa"builtins.float".>>>add_conversion_method(type_from=int,type_to=float,f=float)>>>add(1,2.0)3.0

方法优先级

关键字参数precedence可以设置为整数值以指定 用于打破歧义的方法的优先级:

fromplumimportdispatchclassElement(object):passclassZeroElement(Element):passclassSpecialisedElement(Element):pass@dispatch(ZeroElement,Element)defmul_no_precedence(a,b):return'zero'@dispatch(Element,SpecialisedElement)defmul_no_precedence(a,b):return'specialised operation'@dispatch(ZeroElement,Element,precedence=1)defmul(a,b):return'zero'@dispatch(Element,SpecialisedElement)defmul(a,b):return'specialised operation'
>>>zero=ZeroElement()>>>specialised_element=SpecialisedElement()>>>element=Element()>>>mul(zero,element)'zero'>>>mul(element,specialised_element)'specialised operation'>>>mul_no_precedence(zero,specialised_element)AmbiguousLookupError:Forfunction"mul_no_precedence",signature(__main__.ZeroElement,__main__.SpecialisedElement)isambiguousamongthefollowing:(__main__.ZeroElement,__main__.Element)(precedence:0)(__main__.Element,__main__.SpecialisedElement)(precedence:0)>>>mul(zero,specialised_element)'zero'

参数类

decoratorparametric可用于创建参数类:

fromplumimportdispatch,parametric@parametricclassA(object):# Must be a new-style class!pass@dispatch(A)deff(x):return'fallback'@dispatch(A(1))deff(x):return'1'@dispatch(A(2))deff(x):return'2'
>>>A__main__.A>>>A(1)__main__.A{1}>>>issubclass(A(1),A)True>>>A(1)()<__main__.A{1}at0x10c2bab70>>>>f(A(1)())'1'>>>f(A(2)())'2'>>>f(A(3)())'fallback'

添加多种方法

Dispatcher.multi可用于同时实现多个方法:

fromplumimportdispatch@dispatch.multi((int,int),(float,float))defadd(x,y):returnx+y
>>>add(1,1)2>>>add(1.0,1.0)2.0>>>add(1,1.0)NotFoundLookupError:Forfunction"add",signature(builtins.int,builtins.float)couldnotberesolved.

从另一个包扩展函数

Function.extend可用于扩展特定函数:

frompackageimportf@f.extend(int)deff(x):return'new behaviour'
>>>f(1.0)'old behaviour'>>>f(1)'new behaviour'

直接调用方法

Function.invoke可用于调用给定类型参数的方法:

fromplumimportdispatch@dispatch(int)deff(x):return'int'@dispatch(str)deff(x):return'str'
>>>f(1)'int'>>>f('1')'str'>>>f.invoke(int)('1')'int'>>>f.invoke(str)(1)'str'

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java使用哪个地图/集合?   bluej Java:计算税   由于性能问题,java双精度字符串替代方案   java Eclipse CDT生成设置因重新启动而丢失   如何在java控制台中显示字节流值   java获取url地址,其中是包含我的页面的iframe   java 403禁止的spring启动API调用错误?   如果一个方法返回true,java将停止计时器   使用JavaNIO获取文件创建日期   在Java中从整数转换为二进制时保留整个字节的字符串   java AspectJ&Maven警告:“未应用……中定义的建议?”   java为什么我得到3,我不应该得到+7   java当一个方法包含多个返回的if语句时,如何从该方法中获取返回值?   在运行时循环java(scan.nextLine()!="$")   java配置休眠。cfg。春天的xml   java使用HtmlUnit模拟用户,错误   java CLI如何持续检查更改   java最大素因子(返回)