我们知道,+
运算符可以对两个数字执行加法,合并两个列表,或连接两个字符串。
经过一些调整,我们也可以使用 +
运算符来处理用户定义的[对象] (/python-objects-classes)。Python 中的这项功能,允许同一个运算符根据上下文具有不同的含义,这称为运算符重载。
Python 特殊函数
在 Python 中,名称前后带有两个下划线 __
的方法具有特殊含义。例如,__add__()
、__len__()
等。
这些特殊方法可以用于实现某些功能或行为。
让我们使用 __add__()
方法来添加两个数字,而不是使用 +
运算符。
number1 = 5
# similar to number2 = number1 + 6
number2 = number1.__add__(6)
print(number2) # 11
可以在整数上使用 __add__()
方法,因为
- Python 中的一切都是对象,包括整数。
- 整数定义了我们可以使用的
__add__()
方法。
事实上,+
运算符在内部调用 __add__()
方法来添加整数和浮点数。
以下是 Python 中可用的一些特殊函数
函数 | 描述 |
---|---|
__init__() |
初始化对象的属性。 |
__str__() |
返回对象的字符串表示形式。 |
__len__() |
返回对象的长度。 |
__add__() |
添加两个对象。 |
__call__() |
像普通函数一样调用类的对象。 |
如何使用运算符重载?
假设我们想使用 +
运算符来添加两个用户定义的[对象] (/python-objects-classes)。
由于 +
运算符在内部调用 __add__()
方法,如果我们在类中实现此方法,我们可以使该类的对象与 +
运算符一起使用。
示例:添加两个坐标(不使用重载)
让我们首先编写一个程序来添加两个坐标(不使用 +
运算符重载)。
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def add_points(self, other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y)
p1 = Point(1, 2)
p2 = Point(2, 3)
p3 = p1.add_points(p2)
print((p3.x, p3.y)) # Output: (3, 5)
在上面的示例中,我们创建了 add_points()
方法来添加两个点。为了调用此方法,我们使用了 p1.add_points(p2)
。
让我们使用 +
运算符编写相同的代码来添加两个点。
示例:添加两个坐标(使用重载)
class Point:
def __init__(self, x = 0, y = 0):
self.x = x
self.y = y
def __add__(self, other):
x = self.x + other.x
y = self.y + other.y
return Point(x, y)
p1 = Point(1, 2)
p2 = Point(2, 3)
# this statment calls the __add__() method
p3 = p1 + p2
print((p3.x, p3.y)) # Output: (3, 5)
在这里,p1 + p2
这段代码调用 __add__(self, other)
方法。self
参数接收 p1,而 other 参数接收 p2 作为参数。
不要滥用运算符
在上面的程序中,我们本可以很容易地将 +
运算符用于减法,如下所示
def __add__(self, other):
x = self.x - other.x
y = self.y - other.y
return Point(x, y)
现在上面代码中的 +
运算符执行点的减法。即使程序没有错误,你也应该绝对避免这样做。在运算符重载期间,我们应该始终适当地使用运算符。
同样,我们也可以重载其他运算符。我们需要实现的特殊函数如下表所示。
运算符 | 表达式 | 内部 |
---|---|---|
加法 | 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__() |
重载比较运算符
Python 运算符重载不限于算术运算符。我们也可以重载比较运算符。
这是一个示例,说明我们如何重载 <
运算符,以根据其 age
比较 Person 类的两个对象
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# overload < operator
def __lt__(self, other):
return self.age < other.age
p1 = Person("Alice", 20)
p2 = Person("Bob", 30)
print(p1 < p2) # prints True
print(p2 < p1) # prints False
输出
True False
在这里,__lt__()
重载 <
运算符以比较两个对象的 age 属性。
__lt__()
方法返回
True
- 如果第一个对象的 age 小于第二个对象的 ageFalse
- 如果第一个对象的 age 大于第二个对象的 age
同样,我们需要实现以重载其他比较运算符的特殊函数如下表所示。
运算符 | 表达式 | 内部 |
---|---|---|
小于 | 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) |
运算符重载的优点
以下是运算符重载的一些优点
- 通过允许使用熟悉的运算符来提高代码可读性。
- 确保类的对象与内置类型和其他用户定义类型行为一致。
- 简化代码编写,特别是对于复杂数据类型。
- 通过实现一个运算符方法并将其用于其他运算符,实现代码重用。
另请阅读