`==`运算符何时与`is`运算符不等价?(Python)

12 投票
4 回答
4888 浏览
提问于 2025-04-16 03:44

我注意到我可以用 == 这个符号来比较所有的基本数据类型,比如整数、字符串、布尔值、浮点数等等,还有列表、元组、集合和字典,这些里面也可以包含基本数据类型。在这些情况下,== 会检查两个对象是否相等。但是在某些其他情况下,比如我尝试比较我自己创建的类的实例时,== 只是检查这两个变量是否指向同一个对象(所以在这些情况下,==is 的作用是一样的)

我的问题是:== 这个符号什么时候会做的不只是比较身份呢?

编辑:我使用的是 Python 3

4 个回答

7

在处理整数时,== 不仅仅是比较两个对象是否是同一个,它还会检查这两个整数的值是否相等。举个例子:

>>> x=10000
>>> y=10000
>>> x==y,x is y
(True, False)
>>> del x
>>> del y
>>> x=10000
>>> y=x
>>> x==y,x is y
(True, True)

Python的“标准”实现对小整数做了一些特别处理,所以当你用小的数值进行比较时,可能会得到不同的结果。我们来看看与 10000 相同的情况:

>>> del y
>>> del x
>>> x=1
>>> y=1
>>> x==y,x is y
(True, True)
18

==is 这两个东西在概念上是完全不同的:前者是用来比较两个对象的内容是否相等,而后者则是用来检查两个对象是否是同一个对象,没有任何其他的比较。你可能感到困惑的地方在于,object.__eq__(用户自己写的类如果没有重写这个方法,默认会继承这个方法)实际上是通过检查对象的身份来实现的。毕竟,一个普通的 object 其实没有其他东西可以比较,除了它自己的身份,所以它还能做什么呢?

[1] 为了简单起见,这里省略了 __cmp__ 方法的旧概念,这个方法只是稍微复杂了一点,但对段落的主要意思没有影响;-).

20

在Python中,==这个操作符是通过一个叫做魔法方法__eq__来实现的。默认情况下,它是通过比较对象的身份来判断是否相等。不过,你可以重写这个方法,来定义你自己认为的对象相等的标准。需要注意的是,如果你重写了__eq__,通常还需要重写至少__ne__(这个方法实现了!=操作符)和__hash__,后者是用来计算实例的哈希值的。

我发现,即使在Python中,让我的__eq__实现遵循Java语言中关于equals方法的规则是非常有帮助的,这些规则包括:

  • 自反性:对于任何非空的引用值x,x.equals(x)应该返回true。
  • 对称性:对于任何非空的引用值x和y,x.equals(y)返回true当且仅当y.equals(x)也返回true。
  • 传递性:对于任何非空的引用值x、y和z,如果x.equals(y)返回true并且y.equals(z)返回true,那么x.equals(z)也应该返回true。
  • 一致性:对于任何非空的引用值x和y,多次调用x.equals(y)应该始终返回true或者始终返回false,只要在比较对象时没有修改任何信息。
  • 对于任何非空的引用值x,x.equals(null)应该返回false。

最后一条可能应该把null换成None,但在Python中,这些规则并没有Java那么简单。

撰写回答