使用 `==` 进行比较是不是会在比较值之前比较身份?

Posted

技术标签:

【中文标题】使用 `==` 进行比较是不是会在比较值之前比较身份?【英文标题】:Does comparing using `==` compare identities before comparing values?使用 `==` 进行比较是否会在比较值之前比较身份? 【发布时间】:2016-01-05 19:39:58 【问题描述】:

如果我使用== 比较两个变量,Python 是否会比较身份,如果它们不相同,则比较值?

例如,我有两个指向同一个字符串对象的字符串:

>>> a = 'a sequence of chars'
>>> b = a

这是比较值还是只比较 id?:

>>> b == a
True

首先比较身份是有意义的,我猜是这样,但我还没有在文档中找到任何支持这一点的东西。我最接近的是this:

x==y 呼叫x.__eq__(y)

这并没有告诉我在调用 x.__eq__(y) 之前是否完成了任何操作。

【问题讨论】:

Python 回退相等 - 如果__eq__ 未定义,a == b 被评估为a is b,以确保比较总是有结果。 @jonrsharpe 这就是我的预期。它是否记录在任何地方? @jonrsharpe 实际上,这不是我所期望的。如果定义了__eq__,它会不会先检查id 【参考方案1】:

对于用户定义的类实例,is 用作备用 - 其中默认 __eq__ 未被覆盖,a == b 被评估为 a is b。这确保了比较总是有结果(NotImplemented 情况除外,其中明确禁止比较)。

这是data model documentation(强调我的)中提到的(有点倾斜 - 好地方Sven Marnach):

用户定义的类有__eq__()__hash__()方法 默认;与他们,所有对象比较不相等(除了 他们自己)x.__hash__() 返回一个适当的值,如 x == y 意味着 x is yhash(x) == hash(y)


你可以如下演示:

>>> class Unequal(object):
    def __eq__(self, other):
        return False


>>> ue = Unequal()
>>> ue is ue
True
>>> ue == ue
False

所以__eq__必须在id之前调用,但是:

>>> class NoEqual(object):
    pass

>>> ne = NoEqual()
>>> ne is ne
True
>>> ne == ne
True

所以id 必须在未定义__eq__ 的地方调用。


您可以看到这个in the CPython implementation,其中说明:

/* If neither object implements it, provide a sensible default
   for == and !=, but raise an exception for ordering. */

实现的“合理默认值”是指针vw的C级相等比较,无论它们是否指向同一个对象,都会返回。

【讨论】:

那么,如果我们正在实现__eq__,并且它是有意义的,我们是否应该首先检查id @PeterWood 你可以这样做,是的 - 在比较复杂的地方,它肯定会更有效 @jonrsharpe Cpython 行解释了这一点! 我检查了字符串的代码。蟒蛇checks is first。非常感谢您的指导。 回退到用户定义类的对象标识不是 CPython 实现细节。它是语言规范的一部分,但记录在 a slightly unexpected place。【参考方案2】:

除了@jonrsharpe 的回答:如果被比较的对象实现__eq__,那么 Python 首先检查身份将是错误

看下面的例子:

>>> x = float('nan')
>>> x is x 
True
>>> x == x
False

NaN 是一个特定的东西,永远不应该与它自己进行比较;然而,即使在这种情况下x is x 也应该返回True,因为is 的语义。

【讨论】:

嗯,是的,NaN 是一个例外。在很多情况下,Python 实际上确实 假设对象标识意味着相等。这些情况通常会导致float('nan') 出现意外行为,例如使用NaN as a dictionary key 或检查float('nan') in list_of_floats(如果您要检查的确切float('nan') 对象在列表中,则后者只会产生True,而不是任何NaN )。因此,认为 Python 首先检查身份是“错误的”似乎有点不对劲。

以上是关于使用 `==` 进行比较是不是会在比较值之前比较身份?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 比较操作符,严格比较===

与 0 进行比较与与某个值进行比较是不是更快?

如果将字符串与整数进行比较,它会评估为false吗?

django - 在保存之前比较新旧字段值

如何在更新/插入之前创建一个异常,我必须将一个表的属性值与另一个表的属性值进行比较?

使用 Powershell“where”命令与值数组进行比较