=操作与“;不是”;

这个问题的注释中,我看到了一条建议使用

result is not None

vs

result != None

我想知道有什么不同,为什么一个可能比另一个更值得推荐?

266875 次浏览

None是一个单例对象,因此身份比较总是有效的,而对象可以通过.__eq__()伪造相等比较。

==是一个平等的测试。它检查右边和左边是否相等的对象(根据它们的__eq____cmp__方法)。

is是一个身份测试。它检查右边和左边是不是同一个对象。没有方法调用,对象不能影响is操作。

对于单例对象,可以使用is(和is not),比如None,其中不关心可能想要假装为None的对象,或者希望在与None比较时防止对象损坏。

考虑以下几点:

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)
>>> () is ()
True
>>> 1 is 1
True
>>> (1,) == (1,)
True
>>> (1,) is (1,)
False
>>> a = (1,)
>>> b = a
>>> a is b
True

有些对象是单例对象,因此带有它们的is等价于==。大多数都不是。

首先,让我回顾一下几个术语。如果你只是想回答你的问题,向下滚动到“回答你的问题”。

定义

对象标识:当你创建一个对象时,你可以把它赋值给一个变量。然后还可以将它赋值给另一个变量。和另一个。

>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True

在这种情况下,cancelclosedismiss都指向内存中的同一个对象。你只创建了一个Button对象,所有三个变量都指向这个对象。我们说cancelclosedismiss都指向相同的对象;也就是说,它们指向一个对象。

对象平等:当你比较两个对象时,你通常不关心它在内存中引用确切的相同的对象。使用对象相等,您可以为两个对象如何比较定义自己的规则。当你写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字符串,ab。它们具有完全相同的内容,但它们在内存中不是相同的对象。但是,当我们比较它们时,我们希望它们相等。这里发生的事情是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

这里,我有两个戴尔显示器,ab。它们的牌子和型号都一样。但是,它们既没有相同的数据,也不是内存中的相同对象。但是,当我们比较它们时,我们希望它们相等。这里发生的事情是Monitor对象实现了__eq__方法。

class Monitor(object):
# ...


def __eq__(self, other):
return self.make == other.make and self.model == other.model

回答你的问题

当与None比较时,总是使用is not。None在Python中是单例的——它在内存中只有一个实例。

通过比较身份,这可以非常快地执行。Python检查所引用的对象是否与全局None对象具有相同的内存地址——这是两个数字之间非常非常快的比较。

通过比较平等, Python必须查找对象是否有__eq__方法。如果没有,则检查每个超类,寻找__eq__方法。如果它找到一个,Python就调用它。如果__eq__方法很慢,并且当它注意到另一个对象是None时没有立即返回,这尤其糟糕。

你没有实现__eq__吗?然后Python可能会在object上找到__eq__方法并使用它——无论如何,它只是检查对象标识。

当比较Python中的大多数其他东西时,你将使用!=