Home » python » Python运算符重载
Updated
2017-03-24 19:24
Python运算符重载
运算符重载是一个有很大争议的话题,在C++语言当中被广泛的使用,但是其继任者Java却完全没有给程序员进行运算符重载的机会。Java的设计者认为运算符重载极可能会被滥用而带来很多问题,但Java之外的大多数语言都保留了运算符重载的特性。Java的设计者的考虑并非全无道理,但是技术只是工具,并没有好坏,只有运用的好坏,任何特性都可能被滥用或者发扬光大,我认为并不应该操作符重载可能被滥用就将其完全删去,毕竟有很多能够很好的运用这项技术并能以此写出很好的代码得程序员。应该把是否使用操作符重载交给程序员来决定。
Python当中的运算符重载
在Python当中,程序员可以使用操作符重载,但同时又有着很多的限制。顺便提一下,很多人说Python是一门比较简单的语言,我其实并不太同意。确实Python入门比较简单,能够很快调用一些现有的库来做出一些东西,但这很大意义上只是API的调用,在其背后有着一些很复杂的东西,包括内存模型、继承、抽象类、集合、函数其实都有很多繁琐的细节,希望能够慢慢都把这些慢慢沉淀,写出博客,下面还是回到正题,python的运算符重载。
Python运算符重载的限制
Python在保留运算符重载的同时,也有很多的限制:
无法对内置的对象进行操作符的重载
无法构造新的运算符
某些运算符不能被重载(is,and,or,not,但是其位运算的版本&,|,~,可以被重载)
一元运算符
Python的运算符重载概念上都很简单,也就是需要实现相关的特殊方法,首先看一元运算符,python当中的一元运算符主要有三个,-(取反)、+(一元加)和~(按位取反),其对应的特殊方法分别是__neg__,__pos__,__invert__。其都只接受一个参数,也就是受运算的的值。其中值得一提的是__pos__,其一般就返回自身:
def __pos__(self):
return Vector(self)
也就是说,一般来说x 就 == + x, 但是在标准类库当中也有例外的情况,比如decimal类,设置不同的精度就可能会导致x == +x 为假的情况。
加号
加减乘除的重载是比较常用的,加号重载对应的特殊方法是__add__,这里有一个需要注意的问题就是,有的时候a + b能够得到正确的结果但是b + a却会报出错误,这是应为 a 实现了__add__方法,但是b没有实现,由于可能b是内置类型,我们也无法为其实现__add__方法,这时候我们可以实现__radd__方法,这样b + a也能顺利执行,需要注意的是__radd__的方法比__add__的优先级要低。下面是__radd__的常见实现。
def __radd__(self,other):
return other + self
所有可以重载的二元运算符和其对应的特殊方法如下
+ __add__
- __sub__
* __mul__
/ __truediv__
// __floordiv__
% __mod__
divmod() __divmod__
**,pow() __pow__
@(python3.5新增的矩阵运算)
& __and__
| __or__
^ __xor__
<< __lshift__
>> __shift__
这里有一个细节问题是,在操作符重载当中,很容易出现类型错误的情况,这里比较好的一种实践是捕获错误,在except块当中抛出NotImplemented
def __add__(self,other):
try:
return ...
except TypeError:
return NotImplemented
比较运算符和赋值运算符
比较运算符有六个==(__eq__),!=(__ne__),>=(__ge__),<=(__le__),>(__gt__),和
最后是关于+=(如前面所列共有14种)这一类的运算符,只要我们实现了__add__方法,就可以正常的使用 += 运算符了,这时候python解释器会把 a += b 看成一个语法糖,解释器会将其解释为 a = a + b。除此之外,我们也可以实现 += 对应的特殊方法__iadd__(其他运算同理),直接对a进行操作,__iadd__函数一般就返回self。这两者的不同是前者是a+b产生一个新的对象,然后将其赋给a,而后者是直接在a上进行操作。