使用 `==` 进行比较是不是会在比较值之前比较身份?
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 y
和hash(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. */
实现的“合理默认值”是指针v
和w
的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 首先检查身份是“错误的”似乎有点不对劲。以上是关于使用 `==` 进行比较是不是会在比较值之前比较身份?的主要内容,如果未能解决你的问题,请参考以下文章