上一章Python教程请查看:python3多重继承
可以根据使用的操作数更改Python中操作符的含义。这种做法称为操作超载。
Python中的操作符重载是什么?Python操作符用于内置类,但是相同的操作符对不同的类型有不同的行为,例如,+运算符将对两个数字执行算术加法,合并两个列表并连接两个字符串。
Python中允许相同的操作符根据上下文具有不同的含义的特性称为操作符重载。
那么,当我们将它们与用户定义类的对象一起使用时会发生什么呢?让我们考虑下面的类,它试图模拟二维坐标系中的一个点。
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
现在,运行代码并尝试在Python shell中添加两个点。
>>> p1 = Point(2,3)
>>> p2 = Point(-1,2)
>>> p1 + p2
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for +: 'Point' and 'Point'
出错了!由于Python不知道如何将两个Point对象添加在一起,所以引发了TypeError。
然而,好消息是,我们可以通过操作符重载在Python试下这一点,但首先,我们先来了解一下特殊函数。
Python中的特殊函数以双下划线__开头的类函数在Python中称为特殊函数。这是因为,他们不是普通人,我们在上面定义的_init__()函数就是其中之一,每次我们创建该类的新对象时,它都会被调用,Python中有大量的特殊函数。
使用特殊函数,我们可以使类与内置函数兼容。
>>> p1 = Point(2,3)
>>> print(p1)
<
__main__.Point object at 0x00000000031F8CC0>
打印得不好。但是如果我们在类中定义了_str__()方法,我们就可以控制它的输出方式,我们把这个加到我们的类中。
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = ydef __str__(self):
return "({0},{1})".format(self.x,self.y)
现在让我们再次尝试print()函数。
>>> p1 = Point(2,3)
>>> print(p1)
(2,3)
这是更好的,原来,当我们使用内置函数str()或format()时,会调用相同的方法。
>>> str(p1)
'(2,3)'
>>> format(p1)
'(2,3)'
因此,当你执行str(p1)或format(p1)时,Python在内部执行p1. str__(),这就是特殊函数的名字。
好,现在回到操作符重载。
在Python中重载+运算符为了重载+号,我们需要在类中实现add__()函数。能力越大,责任越大。我们可以在这个函数里做任何想做的事,但是返回一个坐标和的Point对象是明智的。
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = ydef __str__(self):
return "({0},{1})".format(self.x,self.y)def __add__(self,other):
x = self.x + other.x
y = self.y + other.y
return Point(x,y)
现在我们再做一次加法。
>>> p1 = Point(2,3)
>>> p2 = Point(-1,2)
>>> print(p1 + p2)
(1,5)
实际发生的是,当你执行p1 + p2时,Python会调用p1. add__(p2),而p1. add__(p1,p2)又是point . add__(p1,p2)。类似地,我们也可以重载其他操作符。我们需要实现的特殊函数如下表所示。
Python中操作符重载特殊函数
操作符 | 表达式 | 在内部 |
加法 | p1 + p2 | p1.__add__(p2) |
减法 | p1 – p2 | p1.__sub__(p2) |
乘法 | p1 * p2 | p1.__mul__(p2) |
幂 | p1 ** p2 | p1.__pow__(p2) |
除法 | p1 / p2 | p1.__truediv__(p2) |
向下除法 | p1 // p2 | p1.__floordiv__(p2) |
取余(模) | p1 % p2 | p1.__mod__(p2) |
按位左移 | p1 < < p2 | p1.__lshift__(p2) |
逐位右移 | p1 > > p2 | p1.__rshift__(p2) |
位与 | p1 & p2 | p1.__and__(p2) |
按位或 | p1 | p2 | p1.__or__(p2) |
按位异或 | p1 ^ p2 | p1.__xor__(p2) |
位非 | ~p1 | p1.__invert__() |
假设,我们想在Point类中实现小于符号< symbol。
让我们比较一下这些点在原点的大小,然后返回结果,它可以实现如下。
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = ydef __str__(self):
return "({0},{1})".format(self.x,self.y)def __lt__(self,other):
self_mag = (self.x ** 2) + (self.y ** 2)
other_mag = (other.x ** 2) + (other.y ** 2)
return self_mag <
other_mag
尝试在Python shell中运行这些示例。
>>> Point(1,1) <
Point(-2,-3)
True
>>> Point(1,1) <
Point(0.5,-0.2)
False
>>> Point(1,1) <
Point(1,1)
False
类似地,我们需要实现的重载其他比较运算符的特殊函数如下表所示。
【python3运算符重载 – Python3教程】Python中的比较运算符重载
操作符 | 表达式 | 内部 |
小于 | p1 < p2 | p1.__lt__(p2) |
小于或等于 | p1 < = p2 | p1.__le__(p2) |
等于 | p1 == p2 | p1.__eq__(p2) |
不等于 | p1 != p2 | p1.__ne__(p2) |
大于 | p1 > p2 | p1.__gt__(p2) |
大于或等于 | p1 > = p2 | p1.__ge__(p2) |
推荐阅读
- 六大算法设计技巧(贪婪法、分治法、动态规划、随机化算法、回溯法和分支限界法)
- python3多重继承 – Python3教程
- python3继承 – Python3教程
- python3对象和类 – Python3教程
- python3面向对象编程 – Python3教程
- java|程序员加班实用贴 | 每日趣闻
- 人工智能|GPT-3(现实版的“贾维斯”(还是真“人工”智能?))
- 人工智能|复旦博士生写了130行代码,用OCR和正则表达式快速搞定核酸报告统计!
- java|复旦博士写了130行代码,2分钟解决繁琐核酸报告核查