Python中的!=与"is not"的区别

337 投票
5 回答
285905 浏览
提问于 2025-04-15 18:56

在对这个问题的评论中,我看到有人建议使用

result is not None

而不是

result != None

这两者有什么区别呢?为什么有时候推荐用其中一个而不是另一个呢?

5 个回答

51

考虑以下内容:

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)
183

首先,我来解释几个术语。如果你只想要答案,可以直接往下看“回答你的问题”。

定义

对象身份: 当你创建一个对象时,可以把它赋值给一个变量。然后你也可以把它赋值给另一个变量,甚至更多。

>>> 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。在Python中,None是一个单例——内存中只有一个实例。

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

通过比较相等,Python需要查找你的对象是否有 __eq__ 方法。如果没有,它会检查每个父类,寻找 __eq__ 方法。如果找到了,Python就会调用它。如果 __eq__ 方法很慢,并且在发现另一个对象是 None 时没有立即返回,这样就特别糟糕。

如果你没有实现 __eq__,那么Python可能会找到 object 上的 __eq__ 方法并使用它——而这个方法实际上只是检查对象身份。

在Python中比较大多数其他东西时,你会使用 !=

374

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

is 是一个身份测试。它用来检查左边和右边的东西是否是完全相同的对象。这个操作不会调用任何方法,对象之间不会影响 is 的结果。

你在使用 is(和 is not)时,通常是针对单例对象,比如 None。在这种情况下,你不在乎其他对象是否想要假装成 None,或者你想要避免在与 None 比较时出现对象崩溃的问题。

撰写回答