Python中的!=与"is not"的区别
5 个回答
考虑以下内容:
class Bad(object):
def __eq__(self, other):
return True
c = Bad()
c is None # False, equivalent to id(c) == id(None)
c == None # True, equivalent to c.__eq__(None)
首先,我来解释几个术语。如果你只想要答案,可以直接往下看“回答你的问题”。
定义
对象身份: 当你创建一个对象时,可以把它赋值给一个变量。然后你也可以把它赋值给另一个变量,甚至更多。
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
在这种情况下,cancel
、close
和 dismiss
都指向内存中的同一个对象。你只创建了一个 Button
对象,而这三个变量都指向这个对象。我们说 cancel
、close
和 dismiss
都指向相同的对象;也就是说,它们指向的是同一个对象。
对象相等: 当你比较两个对象时,通常不在乎它们是否指向内存中完全相同的对象。通过对象相等,你可以定义自己的规则来比较两个对象。当你写 if a == b:
时,实际上是在说 if a.__eq__(b):
。这让你可以在 a
上定义一个 __eq__
方法,以便使用你自己的比较逻辑。
相等比较的理由
理由: 两个对象的数据完全相同,但并不相同。(它们在内存中不是同一个对象。)例子: 字符串
>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True
注意:我在这里使用unicode字符串,因为Python足够聪明,可以在内存中重用普通字符串,而不创建新的。
这里,我有两个unicode字符串,a
和 b
。它们的内容完全相同,但在内存中并不是同一个对象。然而,当我们比较它们时,我们希望它们相等。发生的事情是,unicode对象实现了 __eq__
方法。
class unicode(object):
# ...
def __eq__(self, other):
if len(self) != len(other):
return False
for i, j in zip(self, other):
if i != j:
return False
return True
注意:__eq__
在 unicode
上的实现效率肯定比这要高。
理由: 两个对象的数据不同,但如果某些关键数据相同,则被认为是同一个对象。例子: 大多数类型的模型数据
>>> import datetime
>>> a = Monitor()
>>> a.make = "Dell"
>>> a.model = "E770s"
>>> a.owner = "Bob Jones"
>>> a.warranty_expiration = datetime.date(2030, 12, 31)
>>> b = Monitor()
>>> b.make = "Dell"
>>> b.model = "E770s"
>>> b.owner = "Sam Johnson"
>>> b.warranty_expiration = datetime.date(2005, 8, 22)
>>> a is b
False
>>> a == b
True
这里,我有两个戴尔显示器,a
和 b
。它们的品牌和型号相同。然而,它们的数据不同,也不是内存中的同一个对象。然而,当我们比较它们时,我们希望它们相等。发生的事情是,Monitor对象实现了 __eq__
方法。
class Monitor(object):
# ...
def __eq__(self, other):
return self.make == other.make and self.model == other.model
回答你的问题
在比较 None
时,总是使用 is not
。在Python中,None是一个单例——内存中只有一个实例。
通过比较身份,这个过程可以非常快速。Python检查你所指的对象是否与全局的None对象有相同的内存地址——这是两个数字之间非常非常快的比较。
通过比较相等,Python需要查找你的对象是否有 __eq__
方法。如果没有,它会检查每个父类,寻找 __eq__
方法。如果找到了,Python就会调用它。如果 __eq__
方法很慢,并且在发现另一个对象是 None
时没有立即返回,这样就特别糟糕。
如果你没有实现 __eq__
,那么Python可能会找到 object
上的 __eq__
方法并使用它——而这个方法实际上只是检查对象身份。
在Python中比较大多数其他东西时,你会使用 !=
。
==
是一个相等性测试。它用来检查左边和右边的东西是否是相等的对象(根据它们的 __eq__
或 __cmp__
方法)。
is
是一个身份测试。它用来检查左边和右边的东西是否是完全相同的对象。这个操作不会调用任何方法,对象之间不会影响 is
的结果。
你在使用 is
(和 is not
)时,通常是针对单例对象,比如 None
。在这种情况下,你不在乎其他对象是否想要假装成 None
,或者你想要避免在与 None
比较时出现对象崩溃的问题。