Python中的数学运算操作符使用进阶
Python中对象的行为是由它的类型(Type)决定的。所谓类型就是支持某些特定的操作。数字对象在任何编程语言中都是基础元素,支持加、减、乘、除等数学操作。
Python的数字对象有整数和浮点数,支持各种数学操作,比如+,-,*,/等。没有这些操作符,程序中只能使用函数调用的方式进行数学运算,比如add(2,3),sub(5,2)。
程序中操作符的作用与普通数学操作的用法是一致的,使用中更加简便直观。Python中,这些操作符实现是通过定义一些object的特殊方法实现的,比如object.__add__()和object.__sub__()。如果用户在自己定义类时实现上述特殊方法,可以使自定义类的对象支持相应的数学操作,从而模拟数字对象的行为。这其实是达到了操作符重载的效果。
这里通过实现一个具有支持加法运算的中文数字类说明如何在Python中实现一个支持常见的数学操作。ChineseNumber类的基本定义如下。
classChineseNumber: def__init__(self,n): self.num=n self.alphabet=[u'零',u'一',u'二',u'三',u'四', u'五',u'六',u'七',u'八',u'九',u'十'] def__str__(self): sign='负'ifself.num<0else'' returnsign+''.join([self.alphabet[int(s)]forsinstr(abs(self.num))]) def__repr__(self): returnself.__str__()
目前,实现的效果是这样的:
>>>a=ChineseNumber(2) >>>a#调用a.__repr__() 二 >>>print(a)#调用a.__str__() 二
一般数学操作符
定义类时,实现__add__()方法,可以给这个类增加+操作符。给ChineseNumber增加如下方法:
def__add__(self,other): iftype(other)isChineseNumber: returnChineseNumber(self.num+other.num) eliftype(other)isint: returnChineseNumber(self.num+other) else: returnNotImplemented
这时ChineseNumber的对象就可以使用+了。
>>>a,b=ChineseNumber(2),ChineseNumber(10) >>>a+b 十二 >>>a+5 七 >>>a+3.7 TypeError:unsupportedoperandtype(s)for+:'ChineseNumber'and'float'
对于+,a+b相当于调用a.__add__(b).类似地,可以定义其他数学操作符,见下表。
object.__add__(self,other):+ object.__sub__(self,other):- object.__mul__(self,other):* object.__matmul__(self,other):@ object.__truediv__(self,other):/ object.__floordiv__(self,other):// object.__mod__(self,other):% object.__divmod__(self,other):divmod,divmod(a,b)=(a/b,a%b) object.__pow__(self,other[,modulo]):**,pow() object.__lshift__(self,other):<< object.__rshift__(self,other):>> object.__and__(self,other):& object.__xor__(self,other):^ object.__or__(self,other):|
操作数反转的数学操作符(Reflected/SwappedOperand)
>>>2+a TypeError:unsupportedoperandtype(s)for+:'int'and'ChineseNumber'
2是整数类型,它的__add__()方法不支持ChineseNumber类的对象,所以出现了上述错误。定义操作数反转的数学操作符可以解决这个问题。给ChineseNumber类添加__radd__()方法,实现操作数反转的+运算。
def__radd__(self,other): returnself.__add__(other)
对于a+b,如果a没有定义__add__()方法,Python尝试调用b的__radd__()方法。此时,a+b相当于调用b.__radd__(a)。
>>>a=ChineseNumber(2) >>>2+a 四
类似地,可以定义其他操作数反转的数学操作符,见下表。
object.__radd__(self,other):+ object.__rsub__(self,other):- object.__rmul__(self,other):* object.__rmatmul__(self,other):@ object.__rtruediv__(self,other):/ object.__rfloordiv__(self,other):// object.__rmod__(self,other):% object.__rdivmod__(self,other):divmod,divmod(a,b)=(b/a,b%a) object.__rpow__(self,other[,modulo]):**,pow() object.__rlshift__(self,other):<< object.__rrshift__(self,other):>> object.__rand__(self,other):& object.__rxor__(self,other):^ object.__ror__(self,other):|
运算赋值操作符
运算赋值操作符使用单个操作符完成运算和赋值操作,比如a+=b相当于调用a=a+b。为ChineseNumber增加__iadd__()方法,可以实现+=操作符。
def__iadd__(self,other): iftype(other)isChineseNumber: self.num+=other.num returnself eliftype(other)isint: self.num+=other returnself else: returnNotImplemented
此时,
>>>a,b=ChineseNumber(2),ChineseNumber(10) >>>a+=b >>>a 十二 >>>a+7 >>>a 十九
类似地,可以定义其他运算赋值操作符,见下表。
object.__iadd__(self,other):+= object.__isub__(self,other):-= object.__imul__(self,other):*= object.__imatmul__(self,other):@= object.__itruediv__(self,other):/= object.__ifloordiv__(self,other)://= object.__imod__(self,other):%= object.__ipow__(self,other[,modulo]):**= object.__ilshift__(self,other):<<= object.__irshift__(self,other):>>= object.__iand__(self,other):&= object.__ixor__(self,other):^= object.__ior__(self,other):|=
一元数学操作符
一元数学操作符是只有一个操作数的运算,比如取负数的操作符-。-对应的特殊函数是__neg__()。为ChineseNumber添加__neg__()方法,
def__neg__(self): returnChineseNumber(-self.num)
此时,ChineseNumber对象就支持-操作了。
>>>a=ChineseNumber(5) >>>-a 负五
其他一元运算符见下表。
object.__neg__(self):- object.__pos__(self):+ object.__abs__(self):abs() object.__invert__(self):~ object.__complex__(self):complex() object.__int__(self):int() object.__float__(self):float() object.__round__(self):round() object.__index__(self):operator.index()