本篇我们学习 Python 运算符重载,了解如何使用内置运算符操作自定义的类对象。
运算符重载
以下示例创建了一个表示二维空间点的类,包含 x 坐标 和 y 坐标两个属性:
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f'({self.x},{self.y})'
为了实现两个 Point2D 对象相加,我们可以定义一个 add() 方法:
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f'({self.x},{self.y})'
def add(self, point):
if not isinstance(point, Point2D):
raise ValueError('The other must be an instance of the Point2D')
return Point2D(self.x + point.x, self.y + point.y)
如果 point 参数不是 Point2D 类的实例,add() 方法将会返回一个错误;否则,它会返回一个新的 Point2D 对象,该对象的 x 和 y 坐标等于两个点的 x 和 y 坐标之和。
以下代码创建了两个 Point2D 类实例并使用 add() 方法将两个坐标点进行相加:
a = Point2D(10, 20)
b = Point2D(15, 25)
c = a.add(b)
print(c)
输出结果如下:
(25,45)
以上代码可以正常运行,但是 Python 提供了更好的实现方法。除了使用 add() 方法之外,我们还可以使用内置的 + 运算符:
c = a + b
当我们使用 + 运算符操作 Point2D 对象时,Python 会调用对象的 __add__() 方法。以下调用方法效果相同:
c = a + b
c = a.__add__(b)
上面的 __add__() 方法必须返回一个新的 Point2D 对象实例。
使用内置运算符操作自定义类型的功能被称为运算符重载。以下示例中的 Point2D 类实现了 __add__() 方法,可以支持 + 运算符:
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f'({self.x},{self.y})'
def __add__(self, point):
if not isinstance(point, Point2D):
raise ValueError('The other must be an instance of the Point2D')
return Point2D(self.x + point.x, self.y + point.y)
if __name__ == '__main__':
a = Point2D(10, 20)
b = Point2D(15, 25)
c = a + b
print(c)
输出结果如下:
(25,45)
运算符重载的特殊方法
下表列出了各种运算符以及对应的特殊方法:
运算符 | 特殊方法 |
---|
+ | __add__(self, other) | – | __sub__(self, other) | * | __mul__(self, other) | / | __truediv__(self, other) | // | __floordiv__(self, other) | % | __mod__(self, other) | ** | __pow__(self, other) | >> | __rshift__(self, other) | << | __lshift__(self, other) | & | __and__(self, other) | | | ^ | __xor__(self, other) |
例如,我们可以实现 Point2D 类的 __sub__() 方法,支持两个坐标点的减法运算:
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f'({self.x},{self.y})'
def __add__(self, point):
if not isinstance(point, Point2D):
raise ValueError('The other must be an instance of the Point2D')
return Point2D(self.x + point.x, self.y + point.y)
def __sub__(self, other):
if not isinstance(other, Point2D):
raise ValueError('The other must be an instance of the Point2D')
return Point2D(self.x - other.x, self.y - other.y)
if __name__ == '__main__':
a = Point2D(10, 20)
b = Point2D(15, 25)
c = b - a
print(c)
inplace 运算符的重载
某些运算符还提供了 inplace 版本。例如,+ 运算符的 inplace 版本是 += 运算符。
对于不可变类型,例如元组、字符串以及数字,inplace 运算符执行计算操作但不会将结果赋予输入对象。对于可变类型,inplace 运算符直接对原始对象进行修改。
Python 同样为 inplace 运算符重载提供了许多特殊方法:
运算符 | 特殊方法 |
---|
+= | __iadd__(self, other) | -= | __isub__(self, other) | *= | __imul__(self, other) | /= | __itruediv__(self, other) | //= | __ifloordiv__(self, other) | %= | __imod__(self, other) | **= | __ipow__(self, other) | >>= | __irshift__(self, other) | <<= | __ilshift__(self, other) | &= | __iand__(self, other) | | = | ^= | __ixor__(self, other) |
我们来看一个重载 += 运算符的示例。
假设存在一个 cart 对象,我们想要将某个物品添加到购物车中。为此,我们可以为 Cart 类定义一个 add() 方法并调用该方法:
cart.add(item)
另外,我们也可以使用 Cart 类的 += 运算符,它可以为购物车添加一个物品:
cart += item
为了支持 += 运算符,我们需要实现 Cart 类的 __iadd__ 方法。
首先,定义一个 Item 类,它包含三个属性 name、quantity 以及 price。同时,它还拥有一个 amount 属性,返回物品的价格小计:
class Item:
def __init__(self, name, qty, price):
self.name = name
self.qty = qty
self.price = price
@property
def amount(self):
return self.qty * self.price
def __str__(self):
return f'{self.name} {self.qty} ${self.price} ${self.amount}'
其次,定义 Cart 类并实现 __iadd__ 方法:
class Cart:
def __init__(self):
self.items = []
def __iadd__(self, item):
if not isinstance(item, Item):
raise ValueError('The item must be an instance of Item')
self.items.append(item)
return self
@property
def total(self):
return sum([item.amount for item in self.items])
def __str__(self):
if not self.items:
return 'The cart is empty'
return '\n'.join([str(item) for item in self.items])
在 __iadd__ 方法中,如果 item 不是 Item 类的实例,将会抛出 ValueError 错误;否则,将 item 添加到物品列表属性中。
total 属性返回了所有物品的总价。
如果购物车中没有任何物品,__str__ 方法将会返回字符串“The cart is empty”;否则,它会返回一个包含所有物品的字符串。
然后使用 += 运算符将物品添加到购物车中:
if __name__ == '__main__':
cart = Cart()
cart += Item('Apple', 5, 2)
cart += Item('Banana', 20, 1)
cart += Item('Orange', 10, 1.5)
print(cart)
print('-' * 30)
print('Total: $', cart.total)
输出结果如下:
Apple 5 $2 $10
Banana 20 $1 $20
Orange 10 $1.5 $15.0
------------------------------
Total: $ 45.0
总结
|