[译]Python 中的运算符重载

928 阅读4分钟

Python 中的运算符重载

pic credits LocalNav

一种运算符对于不同类型的对象,有不同的使用方式。例如, + 用于整型对象,表示两个数相加;用于字符串,表示连接这两个字符串。

x, y = 10, 20
print(x + y) # 30

a,b = 'John', 'Wick'
print(a + b) # John Wick

**+**运算符因操作对象的类型的不同而执行不同的操作,这种特性称为重载。

运算符的功能因其操作数据的类型而异,我们称之为重载。

+运算符可以用于任意两个对象的相加吗?我们来试试看。

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

v1 = Vector(3, 4)
v2 = Vector(5, 6)
v1 + v2

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-08104d7e1232> in <module>
----> 1 v1 + v2

TypeError: unsupported operand type(s) for +: 'Vector' and 'Vector'

运行这段代码会报错。为什么呢?这是因为 + 运算符不知道如何把两个 Vector 类的对象相加。

在本文中,我们将研究如何将既有的运算符用于自定义对象的操作,同时我们要牢记 Python 语言对操作符重载的一些限制性规则。

这些限制性规则有:

  1. 不允许创建新的运算符,只能重载已有的那些运算符
  2. 不允许重载已有数据类型(如 tuple 、 string 、 list)的某些运算符操作
  3. 某些运算符不能重载,例如 is, or, and, not

在开始学习运算符重载前,我们需要了解 Python 数据模型特殊方法

Python 数据模型可以看作一种 “Python 设计方式”或 “Python 框架”。它告诉你 Python 如何管理对象以及如何对它们进行操作。它描述了一系列 API,你可以使用这些 API 使你定义的对象具备已有数据类型的某些功能,并且可以使用大多数 Python 语言的特性,而且不必实现它们。

特殊方法 → 当你使用 len(collection),Python 解释器调用的是 collection.len() 方法。这里的 len() 就是一个特殊方法。

特殊方法开头和结尾都是 __ ,意为只能由 Python 解释器调用,除非你在进行元编程,不然不要直接调用它。

在 Python 语言中,我们可以使用特殊方法来实现运算符重载。

现在我们进行编码,使 Vector 对象支持 + 运算符。

当我们调用 **+** 这个运算符时,Python 解释器调用了 add(self, other) 这个特殊方法。所以,在我们定义的类中实现 add() 方法,就可以支持 + 运算符。

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x , self.y + other.y)

    def __repr__(self):
        return f'Vector({self.x}, {self.y})'

v1 = Vector(3, 4)
v2 = Vector(5, 6)
v1 + v2
>>> Output: Vector(8, 10)

你会发现,我们的类已经支持 + 运算符,在这个类中还实现了 repr() 方法,当我们调用 print() 方法,解释器调用 str() 方法,如果我们没有提供 repr() 的实现,就会调用原来的 repr() 方法。

注意:除了重载类似于 += 的赋值运算符外,一定要返回一个新建的对象。

再举个重载运算符的例子

当我们使用 **==** 运算符时,Python 解释器会调用 eq(self, other) 这个特殊方法,所以我们通过实现 eq() 方法就可以使某个类支持 == 运算符。

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector(self.x + other.x , self.y + other.y)

    def __repr__(self):
        return f'Vector({self.x}, {self.y})'
    
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

v1 = Vector(3, 4)
v2 = Vector(5, 6)
v1 == v2
>>> Output: False

v3 = Vector(3,4)
v1 == v3
>>> Output: True

在 Python 中,使用特殊方法可以轻松实现运算符重载。关键在于理解数据模型和特殊方法。

这些方法能让你从 Python 的惯用特性中受益,并且能利用强大的标准库。

欲了解 Python 数据模型的更多详情,请参考 Fluent python

这里是 Python 中的特殊方法汇总,可供查阅。

总结

我们从理解什么是运算符重载开始,接着讨论了 Python 中运算符重载的一些限制条件、数据模型和特殊方法,然后在 Vector 类中实现了运算符重载。

希望你喜欢这篇文章。祝你工作顺利,好运连连!

如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏