关于比较:`==`运算符何时不等于`is`运算符? (蟒蛇)

When is the `==` operator not equivalent to the `is` operator? (Python)

我注意到我可以使用==运算符来比较所有本机数据类型(整数,字符串,布尔值,浮点数等)以及包含本机数据类型的列表,元组,集合和字典。 在这些情况下,==运算符检查两个对象是否相等。 但在其他一些情况下(尝试比较我创建的类的实例),==运算符只检查两个变量是否引用相同的对象(因此在这些情况下,==运算符等效于is运算符)

我的问题是:==运算符什么时候做的不仅仅是比较身份?

编辑:我正在使用Python 3


在Python中,==运算符是根据魔术方法__eq__实现的,默认情况下,它通过身份比较来实现。但是,您可以覆盖该方法,以提供您自己的对象相等概念。请注意,如果这样做,通常还会覆盖至少__ne__(实现!=运算符)和__hash__,它会计算实例的哈希码。

我发现,即使在Python中,我的__eq__实现也符合Java语言中为equals方法的实现规定的规则,即:

  • 它是自反的:对于任何非空引用值x,x.equals(x)应该返回true。
  • 它是对称的:对于任何非空引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
  • 它是传递性的:对于任何非空引用值x,y和z,如果x.equals(y)返回true而y.equals(z)返回true,则x.equals(z)应返回true。
  • 它是一致的:对于任何非空引用值x和y,x.equals(y)的多次调用始终返回true或始终返回false,前提是不修改在对象的equals比较中使用的信息。
  • 对于任何非空引用值x,x.equals(null)应返回false。

最后一个应该用None替换null,但是Python中的规则并不像在Java中那么容易。


==is总是在概念上是不同的:前者委托给左手对象的__eq__ [1],后者总是检查身份,没有任何委托。让你感到困惑的是object.__eq__(默认情况下由用户编码的类继承,当然不会覆盖它!)是以身份的形式实现的(毕竟,裸object绝对是没有什么可以检查,除了它的身份,所以还有什么可能呢?! - )。

[1]省略了__cmp__方法的遗留概念,这只是一个边缘的复杂因素,并且在段落的要点中没有任何重要的改变;-)。


当涉及整数时,==不仅仅比较身份。它不只是检查两个整数是否是同一个对象;它实际上确保了它们的值匹配。考虑:

1
2
3
4
5
6
7
8
9
10
>>> 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案例进行比较:

1
2
3
4
5
6
>>> del y
>>> del x
>>> x=1
>>> y=1
>>> x==y,x is y
(True, True)

可能最重要的一点是建议总是使用:

1
if myvalue is None:

1
if myvalue == None:

永远不要使用:

1
if myvalue is True:

但使用:

1
if myvalue:

对于我来说,后来的这一点并不是那么明确,因为我认为有时候将布尔值True与其他True值分开,比如"Alex Martelli",说"Alex Martelli"中没有False(绝对没有,它甚至引发了异常: ))但是"Alex Martelli"中有一个"(就像在任何其他字符串中一样)。