Python!=操作与“不是”

问题:Python!=操作与“不是”

在对此问题的评论中,我看到了一条建议使用的声明

result is not None

result != None

我想知道两者之间的区别是什么,为什么要推荐一个而不是另一个?

In a comment on this question, I saw a statement that recommended using

result is not None

vs

result != None

I was wondering what the difference is, and why one might be recommended over the other?


回答 0

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

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

您可以将is(和is not)用于单例,例如None,您不关心可能假装为的对象,None或者想要与之进行比较时要防止对象破裂的地方None

== is an equality test. It checks whether the right hand side and the left hand side are equal objects (according to their __eq__ or __cmp__ methods.)

is is an identity test. It checks whether the right hand side and the left hand side are the very same object. No methodcalls are done, objects can’t influence the is operation.

You use is (and is not) for singletons, like None, where you don’t care about objects that might want to pretend to be None or where you want to protect against objects breaking when being compared against None.


回答 1

首先,让我再谈几个问题。如果您只是想回答问题,请向下滚动到“回答问题”。

定义

对象标识:创建对象时,可以将其分配给变量。然后,您也可以将其分配给另一个变量。还有一个。

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

在这种情况下,cancelclose,和dismiss都指的是同一个对象在内存中。您仅创建了一个Button对象,并且所有三个变量都引用了该对象。我们说cancelclosedismiss都指同一对象; 也就是说,它们只引用一个对象。

对象相等性:比较两个对象时,通常不必关心它是否指向内存中完全相同的对象。使用对象相等性,您可以定义自己的规则以比较两个对象。当您写作时if a == b:,您实际上是在说if a.__eq__(b):。这使您可以定义一个__eq__方法,a以便可以使用自己的比较逻辑。

平等比较的理由

理由:两个对象具有完全相同的数据,但不完全相同。(它们不是内存中的同一对象。) 示例:字符串

>>> 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__on 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中,没有一个是单例的-内存中只有一个实例。

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

通过比较相等性,Python必须检查您的对象是否具有__eq__方法。如果不是,它将检查每个超类以寻找一种__eq__方法。如果找到一个,Python会调用它。如果该__eq__方法很慢并且在注意到另一个对象为时不立即返回,则尤其糟糕None

你没有实现__eq__吗?然后,Python可能会找到该__eq__方法object并改用该方法-无论如何,它只会检查对象的身份。

在Python中比较大多数其他内容时,您将使用!=

First, let me go over a few terms. If you just want your question answered, scroll down to “Answering your question”.

Definitions

Object identity: When you create an object, you can assign it to a variable. You can then also assign it to another variable. And another.

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

In this case, cancel, close, and dismiss all refer to the same object in memory. You only created one Button object, and all three variables refer to this one object. We say that cancel, close, and dismiss all refer to identical objects; that is, they refer to one single object.

Object equality: When you compare two objects, you usually don’t care that it refers to the exact same object in memory. With object equality, you can define your own rules for how two objects compare. When you write if a == b:, you are essentially saying if a.__eq__(b):. This lets you define a __eq__ method on a so that you can use your own comparison logic.

Rationale for equality comparisons

Rationale: Two objects have the exact same data, but are not identical. (They are not the same object in memory.) Example: Strings

>>> greeting = "It's a beautiful day in the neighbourhood."
>>> a = unicode(greeting)
>>> b = unicode(greeting)
>>> a is b
False
>>> a == b
True

Note: I use unicode strings here because Python is smart enough to reuse regular strings without creating new ones in memory.

Here, I have two unicode strings, a and b. They have the exact same content, but they are not the same object in memory. However, when we compare them, we want them to compare equal. What’s happening here is that the unicode object has implemented the __eq__ method.

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

Note: __eq__ on unicode is definitely implemented more efficiently than this.

Rationale: Two objects have different data, but are considered the same object if some key data is the same. Example: Most types of model data

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

Here, I have two Dell monitors, a and b. They have the same make and model. However, they neither have the same data nor are the same object in memory. However, when we compare them, we want them to compare equal. What’s happening here is that the Monitor object implemented the __eq__ method.

class Monitor(object):
    # ...

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

Answering your question

When comparing to None, always use is not. None is a singleton in Python – there is only ever one instance of it in memory.

By comparing identity, this can be performed very quickly. Python checks whether the object you’re referring to has the same memory address as the global None object – a very, very fast comparison of two numbers.

By comparing equality, Python has to look up whether your object has an __eq__ method. If it does not, it examines each superclass looking for an __eq__ method. If it finds one, Python calls it. This is especially bad if the __eq__ method is slow and doesn’t immediately return when it notices that the other object is None.

Did you not implement __eq__? Then Python will probably find the __eq__ method on object and use that instead – which just checks for object identity anyway.

When comparing most other things in Python, you will be using !=.


回答 2

考虑以下:

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)

Consider the following:

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)

回答 3

None是单例,因此身份比较将始终有效,而对象可以通过伪造相等比较.__eq__()

None is a singleton, therefore identity comparison will always work, whereas an object can fake the equality comparison via .__eq__().


回答 4

>>>()是()
真正
>>> 1是1
真正
>>>(1,)==(1,)
真正
>>>(1,)是(1,)
假
>>> a =(1,)
>>> b = a
>>> a是b
真正

有些对象是单例,因此is与它们等效==。大多数不是。

>>> () is ()
True
>>> 1 is 1
True
>>> (1,) == (1,)
True
>>> (1,) is (1,)
False
>>> a = (1,)
>>> b = a
>>> a is b
True

Some objects are singletons, and thus is with them is equivalent to ==. Most are not.