介绍小编一直觉得我的公众号排版很鸡肋。从本文开始,我将采用全新的排版风格,还特地制作了一个卡通二维码(见文末),希望大家喜欢(不要脸假装粉丝多)。其实,关于排版,小编要衷心感谢靖宇先生的指导。那么,今天我想和大家谈谈如何重载运算符+。仔细阅读本文后,您将获得:理解中缀运算符特殊方法的调度机制理解vector类如何实现__add__方法理解vector类如何调用__radd__方法实现背后的特殊方法a+b?大家都知道,如果a和b是同类型的序列,a+b就可以实现序列拼接。如果a和b都是int或float等数值类型,a+b实现数学加法,见例1。#例1a=(1,2)b=(4,5)print(a+b)#(1,2,4,5)a=[1,2]b=[4,5]print(a+b)#[1,2,4,5]a=b=1print(a+b)#2a=b=1.0print(a+b)#2.0但是如果a和b是不同类型的序列,是否可以拼接成功?要回答这个问题,我们先来了解一下Python为中缀运算符的特殊方法提供的特殊派发机制。过程如下图所示。对于表达式a+b,为了支持涉及不同类型的操作,Python解释器会执行以下步骤。如果a有__add__方法,返回值不为NotImplemented,调用a.__add__(b),返回结果如果a没有__add__方法,或者__add__方法返回NotImplemented,检查b是否有__radd__方法,如果any,如果在调用b.__radd__(a)方法后没有返回NotImplemented,则返回结果。如果b没有__radd__方法,或者调用__radd__方法返回NotImplemented,则抛出TypeError,错误提示不支持操作类型。_radd_是__add__的“反向”版本,Alex、Anna和Leo喜欢将其称为“正确的”特殊方法,因为它们都是在正确的操作数上调用的。如果a和b是不同类型的序列,那么当执行例2中的程序时会发生什么?#例子2a=(1,2)b=[3,4]print(a+b)首先解释器会调用a.__add__(b)方法,因为a和b是不同类型的序列,所以NotImplemented是回。然后解释器检查b是否有b.__radd__(a)方法,然后调用这个方法,但仍然返回NotImplemented,最后抛出TypeError结果。TypeError:canonlyconcatenatetuple(not"list")totupleoverloadedoperator+关于重载运算符,有几点需要注意:内置类型的运算符不能重载,即这些内置类型的操作如因为列表不能超载。您不能创建新的运算符,只能重载现有运算符。有些运算符不能被重载,is、and、orandnot(位运算&、|和~可以)。现在我们尝试定义一个Vector类,见例3。#Example3classVector(object):def__init__(self,components):self.components=list(components)如果我们不重载Vector的运算符+,添加两个Vector类会抛出错误,见例4#Example4v1=Vector([1,2,3])v2=Vector([1,2,3])print(v1+v2)#TypeError:unsupportedoperandtype(s)for+:'Vector'和'Vector',我们现在重载运算符+forVector,见示例5,但我们实现的不是拼接,而是数学加法,因为对于向量来说,拼接功能意义不大。#Example5classVector(object):def__init__(self,components):self.components=list(components)def__iter__(self):returniter(self.components)def__str__(self):returnstr(self.components)复制代码def__add__(self,others):print("__add__")try:pairs=itertools.zip_longest(self,others,fillvalue=0.0)returnVector(a+bfora,binpairs)除了TypeError:returnNotImplementedv1=Vector([1,2,3])v2=Vector([1,2,3])v3=[1,2,3]print(v1+v2)print(v1+v3)输出:__add__[2,4,6]__add__[2,4,6]从示例5可以看出,解析器调用__add__方法来实现两个Vectors或者Vectors和带有数字元素的可迭代类型的相加。例5可以实现V1+V3,是否可以实现V3+v1?参见示例6。#Example6print(V3+V1)#TypeError:canonlyconcatenatelist(not"Vector")tolist示例6抛出错误,当解释器执行v3.__add__(V1)时,因为列表的_调用了自定义类型无法添加_add__方法,所以返回结果NotImplemented,尝试执行V1.__radd__(V3)方法,但是自定义Vector类中没有实现该方法,所以一个最后抛出TypeError。好了,现在尝试实现Vector类的__radd__方法。在例5的基础上增加例7的代码。#Example7def__radd__(self,other):print("__radd__")returnself+other再次运行示例6以获得以下输出。__radd____add__[2,4,6]当解释器执行V3.__dd__(V1)返回NotImplemented时,会调用自定义类中的__radd__方法,__radd__方法将计算结果委托给__add__。事实上,任何交换运算符都可以做到这一点。好了,以上就是小编今天分享的内容,希望对大家有用。公众号:CVpython专注于Python与计算机视觉的分享,扫描二维码关注我!
