Python 运算符重载
提示
- 操作符重载:Python允许用户自定义类中的操作符(如
+
、<
等)的行为,使得相同的操作符在不同上下文中可以有不同的含义。 - 特殊函数的使用:通过实现以双下划线开头和结尾的特殊函数(如
__add__
、__lt__
等),可以定制操作符的行为,以满足特定类的需求。 - 优势和应用:操作符重载提高了代码的可读性和一致性,使得自定义类的对象可以像内置类型那样直观和灵活地进行操作。
在Python中,我们可以更改用户定义类型的操作符的工作方式。
例如,+
操作符可以对两个数字执行算术加法、合并两个列表或连接两个字符串。
Python中允许同一个操作符根据上下文具有不同含义的这一特性称为操作符重载。
Python特殊函数
以双下划线__
开头的类函数在Python中称为特殊函数。
这些特殊函数由Python解释器定义,用于实现某些特性或行为。
它们被称为**"双下划线"**函数,因为它们有双下划线前缀和后缀,如__init__()
或__add__()
。
以下是Python中一些可用的特殊函数,
函数 | 描述 |
---|---|
__init__() | 初始化对象的属性 |
__str__() | 返回对象的字符串表示 |
__len__() | 返回对象的长度 |
__add__() | 加两个对象 |
__call__() | 像普通函数一样调用类的对象 |
示例:Python中的+操作符重载
要重载+
操作符,我们需要在类中实现__add__()
函数。
拥有了巨大的权力就要承担巨大的责任。我们可以在这个函数内部做任何我们喜欢的事情。但更明智的做法是返回坐标和的Point
对象。
让我们看一个例子,
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __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(1, 2)
p2 = Point(2, 3)
print(p1+p2)
# 输出: (3,5)
在上面的例子中,实际发生的是,当我们使用p1 + p2
时,Python调用p1.__add__(p2)
,这实际上是Point.__add__(p1,p2)
。之后,加法操作按照我们指定的方式进行。
类似地,我们也可以重载其他操作符。我们需要实现的特殊函数如下表所示。
操作符 | 表达式 | 内部实现 |
---|---|---|
加法 | 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不仅限制对算术操作符的重载。我们也可以重载比较操作符。
以下是一个例子,展示了我们如何重载<
操作
符,以根据Person类中的age
属性比较两个对象:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 重载 < 操作符
def __lt__(self, other):
return self.age < other.age
p1 = Person("Alice", 20)
p2 = Person("Bob", 30)
print(p1 < p2) # 输出 True
print(p2 < p1) # 输出 False
输出
True
False
在这里,__lt__()
重载了<
操作符,用于比较两个对象的age
属性。
__lt__()
方法返回,
True
- 如果第一个对象的年龄小于第二个对象的年龄False
- 如果第一个对象的年龄大于第二个对象的年龄
类似地,我们需要实现的特殊函数,以重载其他比较操作符如下表所示。
操作符 | 表达式 | 内部实现 |
---|---|---|
小于 | 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) |
操作符重载的优势
以下是操作符重载的一些优势,
- 通过允许使用熟悉的操作符,提高代码的可读性。
- 确保类的对象与内置类型和其他用户定义类型一致地行为。
- 使编写代码变得更简单,特别是对于复杂的数据类型。
- 通过实现一个操作符方法并将其用于其他操作符,实现代码复用。