Python 运算符重载

我们知道,+ 运算符可以对两个数字执行加法,合并两个列表,或连接两个字符串。

经过一些调整,我们也可以使用 + 运算符来处理用户定义的[对象] (/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 小于第二个对象的 age
  • False - 如果第一个对象的 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)

运算符重载的优点

以下是运算符重载的一些优点

  • 通过允许使用熟悉的运算符来提高代码可读性。
  • 确保类的对象与内置类型和其他用户定义类型行为一致。
  • 简化代码编写,特别是对于复杂数据类型。
  • 通过实现一个运算符方法并将其用于其他运算符,实现代码重用。

另请阅读

你觉得这篇文章有帮助吗?

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战