Python! = operación vs "no es"

Resuelto viksit asked hace 14 años • 5 respuestas

En un comentario sobre esta pregunta , vi una declaración que recomendaba usar

result is not None

vs

result != None

¿Cuál es la diferencia? ¿Y por qué podría recomendarse uno sobre el otro?

viksit avatar Feb 06 '10 02:02 viksit
Aceptado

==es una prueba de igualdad . Comprueba si el lado derecho y el lado izquierdo son objetos iguales (según sus métodos __eq__o __cmp__).

isEs una prueba de identidad . Comprueba si el lado derecho y el lado izquierdo son el mismo objeto. No se realizan llamadas a métodos, los objetos no pueden influir en la isoperación.

Usas is(y is not) para singletons, como None, donde no te importan los objetos que podrías querer fingir ser Noneo donde quieres protegerte contra objetos que se rompan al compararlos con None.

Thomas Wouters avatar Feb 05 '2010 19:02 Thomas Wouters

Primero, déjame repasar algunos términos. Si solo desea que se responda su pregunta, desplácese hacia abajo hasta "Responder a su pregunta".

Definiciones

Identidad del objeto : cuando crea un objeto, puede asignarlo a una variable. Luego también puedes asignarlo a otra variable. Y otro.

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

En este caso, cancel, closey dismisstodos se refieren al mismo objeto en la memoria. Solo creó un Buttonobjeto y las tres variables se refieren a este objeto. Decimos que cancel, closey dismisstodos se refieren a objetos idénticos ; es decir, se refieren a un solo objeto.

Igualdad de objetos : cuando comparas dos objetos, normalmente no te importa que se refiera exactamente al mismo objeto en la memoria. Con la igualdad de objetos, puedes definir tus propias reglas sobre cómo se comparan dos objetos. Cuando escribes if a == b:, esencialmente estás diciendo if a.__eq__(b):. Esto le permite definir un __eq__método apara que pueda utilizar su propia lógica de comparación.

Justificación de las comparaciones de igualdad

Justificación: dos objetos tienen exactamente los mismos datos, pero no son idénticos. (No son el mismo objeto en la memoria). Ejemplo: cadenas

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

Nota: aquí uso cadenas Unicode porque Python es lo suficientemente inteligente como para reutilizar cadenas normales sin crear otras nuevas en la memoria.

Aquí tengo dos cadenas Unicode ay b. Tienen exactamente el mismo contenido, pero no son el mismo objeto en la memoria. Sin embargo, cuando los comparamos, queremos que sean iguales. Lo que sucede aquí es que el objeto Unicode ha implementado el __eq__método.

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

Nota: __eq__on unicodedefinitivamente se implementa de manera más eficiente que esto.

Justificación: Dos objetos tienen datos diferentes, pero se consideran el mismo objeto si algunos datos clave son los mismos. Ejemplo: la mayoría de los tipos de datos de modelo

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

Aquí tengo dos monitores Dell ay b. Tienen la misma marca y modelo. Sin embargo, no tienen los mismos datos ni son el mismo objeto en la memoria. Sin embargo, cuando los comparamos, queremos que sean iguales. Lo que sucede aquí es que el objeto Monitor implementó el __eq__método.

class Monitor(object):
    # ...

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

Respondiendo tu pregunta

Al comparar con None, utilice siempre is not. Ninguno es un singleton en Python: solo hay una instancia en la memoria.

Al comparar la identidad , esto se puede realizar muy rápidamente. Python comprueba si el objeto al que te refieres tiene la misma dirección de memoria que el objeto global Ninguno: una comparación muy, muy rápida de dos números.

Al comparar la igualdad , Python tiene que buscar si su objeto tiene un __eq__método. Si no es así, examina cada superclase en busca de un __eq__método. Si encuentra uno, Python lo llama. Esto es especialmente malo si el __eq__método es lento y no regresa inmediatamente cuando nota que el otro objeto es None.

¿ No lo implementaste __eq__? Entonces Python probablemente encontrará el __eq__método objecty lo usará en su lugar, lo que de todos modos solo verifica la identidad del objeto.

Al comparar la mayoría de las otras cosas en Python, usará !=.

Wesley avatar Feb 05 '2010 20:02 Wesley

Considera lo siguiente:

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)
Alok Singhal avatar Feb 05 '2010 20:02 Alok Singhal

Nonees un singleton y, por lo tanto, la comparación de identidad siempre funcionará, mientras que un objeto puede falsificar la comparación de igualdad mediante .__eq__().

Ignacio Vazquez-Abrams avatar Feb 05 '2010 19:02 Ignacio Vazquez-Abrams
>>> () es ()
Verdadero

>>> 1 es 1
Verdadero

>>> (1,) == (1,)
Verdadero

>>> (1,) es (1,)
FALSO

>>> a = (1,)
>>> b = a
>>> a es b
Verdadero

Algunos objetos son singletons y, por lo tanto, iscon ellos es equivalente a ==. La mayoría no lo es.

ephemient avatar Feb 05 '2010 20:02 ephemient