类与面向对象编程(Object-Oriented Programming, OOP)(一)
对象比较:‘is’ 对比 ‘==’
当我还是个孩子的时候,我们的邻居拥有一对双胞胎猫咪。它们看起来几乎一模一样—同样的炭黑色毛发和同样锐利的绿色眼睛。尽管有一些性格上的小特点,但只要你从外表上看它们,就很难分辨出它们之间的区别。
然而,当然这两只是不同的猫咪,是两个独立的生命体,尽管它们长得一模一样。这就引出了“equal”(相等)与 “identical”(完全相同)在含义上的差异,这对理解Python中is和==比较操作符的行为至关重要。
==操作符比较的是值是否相等:如果我们的猫咪是Python对象,并且我们用==来比较它们,我们会得到“两只猫的值是相同的”这样的答案。
而is操作符则是在比较身份:如果我们用is来比较我们的猫咪,我们可能会得到“这两只是不同的猫咪”的信息。
但在我深入这个双胞胎猫咪比喻之前,让我们先来看看一些真实的Python代码。
首先,我们将创建一个新的列表对象,并将其命名为a。然后,我们定义另一个变量b,它指向的是与a相同的列表对象:
>>> a = [4, 5, 6]
>>> b = a
让我们检查一下这两个变量。我们可以看到它们都指向了看起来完全一样的列表:
>>> a
[4, 5, 6]
>>> b
[4, 5, 6]
由于两个列表对象看起来完全一样,当我们使用==操作符来比较它们是否相等时,我们将会得到预期的结果:
>>> a == b
True
然而,这并不告诉我们a和b实际上是否指向同一个对象。当然,我们知道它们确实是指向同一个对象的,因为我们之前赋予了它们这个值。但是假设我们不知道——我们该如何找到答案?
答案是使用is操作符来比较a和b这两个变量。这将确认两者确实是指向同一个Python列表对象:
>>> a is b
True
让我们看看当我们将我们的列表对象创建一个完全相同的副本时会发生什么。我们可以通过在现有列表上调用list()来创建这个副本,我们将这个副本命名为c:
>>> c = list(a)
再次你会看到我们刚刚创建的新列表与a和b所指向的原列表对象看起来完全一样。这是因为在Python中,当我们使用list()函数将一个可迭代对象转换为列表时,生成的是一个新的列表实例,其内容与原始可迭代对象相同。
因此,无论我们将哪个列表复制到新变量上,它们都会保持一致,并且都指向同一个数据结构。
现在事情变得有趣了。让我们比较一下我们的列表复制c与最初的列表a,看看使用==操作符会得到什么答案。你会期待看到什么样的结果呢?
>>> a == c
True
好的,我看到你期待的结果了。这个结果告诉我们c和a具有完全相同的元素内容。在Python中,它们被认为是相等的。
但问题在于,它们只是看起来相同吗?实际上,它们是同一对象的不同引用还是各自独立的对象呢?让我们用is操作符来进一步探究这个问题。
>>> a is c
False
太棒了!这就是我们期待的结果。Python帮我们揭示了一个有趣的事实:c和a实际上是指向两个不同对象的引用,即使它们的内容完全相同。
为了简洁地概括这个区别,我们可以为is和==这两个概念提供如下定义:
- is:用于检查两个对象是否是同一个对象。如果它们是同一个对象(即具有相同的类和/或引用),则返回True;否则返回False。
- ==:通常用来比较两个变量的值是否相同。它会检查对象的内容,而不是它们本身。因此,如果c和a内容相等,但它们不是同一个对象,那么c == a将返回True。
只需记住,在需要决定使用Python中的is和==时,只要想到一对双胞胎猫咪(狗狗也可以)就行了。如果你这样做,你就不会有问题了。