值相等还是引用相等?比较运算符“==”是用来干什么的?

4
许多教程都说==比较运算符用于值相等,就像这个answer中的引用所示:
==用于值相等。当您想知道两个对象是否具有相同的值时,请使用它。”
is用于引用相等。当您想知道两个引用是否指向同一个对象时,请使用它。”
然而,我发现Python的doc说:
x==y调用x.__eq__(y)。默认情况下,object通过使用is实现__eq__(),在假比较的情况下返回NotImplementedTrue if x is y else NotImplemented。”
似乎 == 运算符的默认行为是像 is 运算符一样比较引用质量,这与这些教程所说的相矛盾。
那么我应该使用 == 来做什么呢?值相等还是引用相等?还是取决于如何实现 __eq__ 方法。

我认为值比较的文档已经清楚地阐述了这个问题:

<>==>=<=!=运算符比较两个对象的值。在Python中,一个对象的值是一个相当抽象的概念。比较运算符实现了一个特定的对象值的概念。人们可以将它们视为通过比较实现对象值间接定义的手段。

默认相等比较的行为即不同标识的实例总是不相等,与那些需要合理定义对象值和基于值相等性的类型的需求可能相矛盾。这样的类型将需要自定义它们的比较行为,事实上,许多内置类型已经这样做了。

默认情况下,对象的等值比较(==!=)基于对象的标识。因此,具有相同标识的实例之间的等值比较结果为相等,而具有不同标识的实例之间的等值比较结果为不相等。此默认行为的动机是希望所有对象都应该是自反的(即x is y意味着x == y)。此外,它还包括一个列表,描述了最重要的内置类型(如数字、字符串和序列等)的比较行为。
4个回答

3

object 通过使用 is 实现 __eq__(),但标准库中的许多类使用值相等性实现 __eq__()。例如:

>>> l1 = [1, 2, 3]
>>> l2 = [1, 2, 3]
>>> l3 = l1
>>> l1 is l2
False
>>> l1 == l2
True
>>> l1 is l3
True

在您自己的类中,您可以按照自己的意愿实现__eq__()方法,例如:

class Point():
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __eq__(self, other):
        return self.x == other.x and self.y == other.x

3

这完全取决于__eq__的行为方式。类型object的默认__eq__的行为类似于is。某些内置数据类型使用自己的实现方式。例如,当且仅当两个列表的所有值都相等时它们才相等。你只需要知道这些。


0

为了用简单的定义来补充您的思考过程,

等号运算符==比较两个操作数的值并检查值是否相等。而is运算符则检查两个操作数是否引用同一个对象(存在于同一内存位置)。

简而言之,is检查两个引用是否指向同一个对象。== 检查两个对象的值是否相同。

例如:

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 

-1
one = 1
a = one
b = one
if (a == b): # this if works like this: if (1 == 1)
if (a is 1): # this if works like this: if (int.object(1, memory_location:somewhere) == int.object(1, memory_location:variable.one))

因此,a为1是无效的,因为它的参数未指向相同的位置。

1
a is 1 在 Python 3.9 中会引发 SyntaxWarning - Daniel Hepper
今天我了解到SyntaxWarning,很不错。根据快速测试,似乎在使用Python 3.8时,当代码中出现a is 1时会生成该警告。 - Chris
实际上,从我的测试中a is 1返回了True,我认为这是因为Python有一个缓存池用于常见的整数,比如1,它们只会被创建一次。 - oeter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接