在 Python 中,运算符重载允许同一个运算符根据不同的数据类型表现出不同的行为。
- Python 内置的数据类型允许 INLINECODEbacfea77 运算符用于数字相加、字符串连接或列表合并,同时也允许 INLINECODE9cfb994f 运算符用于重复字符串实例。
- Python 还允许我们对用户自定义的类进行运算符重载,只需编写如 INLINECODEb3a36835、INLINECODE72b08efd、INLINECODEb65323f0、INLINECODE49f5d579、INLINECODE160964f4 和 INLINECODE27762a90 这样的方法,就能让对象分别支持 INLINECODE3c2ab195、INLINECODE66e95d7a、INLINECODE3f1be065、INLINECODE39b67966、INLINECODE8b699b9f 和 INLINECODE58564b52 等运算符。
- 我们无法全局覆盖或更改内置类型(如 INLINECODEdc6cd886、INLINECODE1bf6b51f、
list)的运算符行为,但我们可以对它们进行子类化(或定义我们自己的类)并实现这些特殊方法。
下面的例子展示了像 INLINECODEcc3ea8f6 和 INLINECODE25fbbce7 这样的内置运算符是如何根据数据类型的不同而产生不同结果的。
Python
# + 运算符用于整数
print(1 + 2)
# + 运算符用于字符串(连接)
print("Geeks" + "For")
# * 运算符用于数字
print(3 * 4)
# * 运算符用于字符串(重复)
print("Geeks" * 4)
输出
3
GeeksFor
12
GeeksGeeksGeeksGeeks
用户自定义类型的运算符重载
当我们对用户自定义的对象使用运算符时,Python 并不知道如何处理它。为了让运算符作用于自定义类,Python 提供了特殊方法(也被称为魔法方法)。
> + 运算符 -> 调用 add(self, other)
> – 运算符 -> 调用 sub(self, other)
> == 运算符 -> 调用 eq(self, other)
所以,当我们编写 obj1 + obj2 时,Python 内部实际上是在调用:
> obj1.add(obj2)
如果在类中定义了这个方法,运算符重载就生效了。
示例 1: 这段代码展示了如何在自定义类中重载 + 运算符,以处理整数和字符串的加法。
Python
class A:
def __init__(self, a):
self.a = a
# 定义 + 的行为
def __add__(self, o):
return self.a + o.a
ob1 = A(1)
ob2 = A(2)
ob3 = A("Geeks")
ob4 = A("For")
print(ob1 + ob2) # 整数加法
print(ob3 + ob4) # 字符串连接
# 实际的工作方式(内部原理)
print(A.__add__(ob1, ob2))
print(ob1.__add__(ob2))
输出
3
GeeksFor
3
3
解释:
- INLINECODE617e2faf 会自动调用 INLINECODE538afb2c。
- Python 将其转化为
A.__add__(ob1, ob2)。 - 第一个操作数(ob1)变成 INLINECODEd33bcf14,第二个操作数(ob2)变成 INLINECODEea285314。
示例 2: 这段代码展示了如何为自定义的 Complex 类重载 + 运算符,使其分别将实部和虚部相加。
Python
class Complex:
def __init__(self, a, b):
self.a = a
self.b = b
def __add__(self, other):
return self.a + other.a, self.b + other.b
Ob1 = Complex(1, 2)
Ob2 = Complex(2, 3)
Ob3 = Ob1 + Ob2
print(Ob3)
输出
(3, 5)
解释: 这里,Ob1 + Ob2 分别将实部(1+2)和虚部(2+3)进行了相加。
重载比较运算符
像 INLINECODEb513f4f2、INLINECODE16a3d3e3 和 == 这样的运算符也可以被重载。
示例 1: 这段代码展示了如何重载 > 运算符,以根据存储的值比较两个对象。
Python
class A:
def __init__(self, a):
self.a = a
def __gt__(self, other):
return self.a > other.a
ob1 = A(2)
ob2 = A(3)
if ob1 > ob2:
print("ob1 is greater than ob2")
else:
print("ob2 is greater than ob1")
输出
ob2 is greater than ob1
示例 2: 这段代码展示了如何重载 INLINECODE75b0d0a0 和 INLINECODE78ef4e80 运算符以进行自定义比较。
Python
class A:
def __init__(self, a):
self.a = a
def __lt__(self, other):
return "ob1 is less than ob2" if self.a < other.a else "ob2 is less than ob1"
def __eq__(self, other):
return "Both are equal" if self.a == other.a else "Not equal"
ob1 = A(2)
ob2 = A(3)
print(ob1 < ob2)
ob3 = A(4)
ob4 = A(4)
print(ob3 == ob4)
输出
ob1 is less than ob2
Both are equal
非结合性运算符
并非所有运算符都可以链接使用。有些是非结合性的。例如,INLINECODEaa3e71fc 和 INLINECODE25df17a8 不能在同一个语句中组合使用。
Python
a = 5
b = 10
c = 15
# 无效:混合了赋值 (=) 和 +=
# a = b = (a < b) += (b < c)
解释: 在 Python 中,INLINECODE703933c0(赋值)和 INLINECODE382604de(增强赋值)不能在同一个表达式中混合使用,因为它们是非结合性的。
重载布尔运算符
我们还可以使用魔法方法重载布尔运算符:
- and: and(self, other)
- or: or(self, other)
- not: not(self)
示例: 这段代码展示了如何重载 & 运算符,使其在自定义对象上像逻辑 AND 那样工作。
Python
class MyClass:
def __init__(self, value):
self.value = value
def __and__(self, other):
return MyClass(self.value and other.value)
a = MyClass(True)
b = MyClass(False)
c = a & b
print(c.value)
输出
False
解释: 当我们对 INLINECODEcba06a53 和 INLINECODE6fa2f874 执行 INLINECODE5b3cc887 操作时,Python 调用 INLINECODEc953c3de 对象上定义的 INLINECODE13455b64 方法。在这个方法中,我们使用 Python 内置的 INLINECODE378a85c5 逻辑比较了两个对象的 INLINECODE146be449 属性,并返回了一个包含结果的新 INLINECODE110f550c 对象。