En un comentario sobre esta pregunta , vi una declaración que recomendaba usar
result is not None
vs
result != None
Me preguntaba cuál es la diferencia y por qué uno podría recomendarse sobre el otro.
En un comentario sobre esta pregunta , vi una declaración que recomendaba usar
result is not None
vs
result != None
Me preguntaba cuál es la diferencia y por qué uno podría recomendarse sobre el otro.
Respuestas:
==
Es una prueba de igualdad . Se comprueba si el lado derecho y el lado izquierdo son iguales objetos (según su __eq__
o __cmp__
métodos.)
is
Es 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 is
operación.
Utiliza is
(y is not
) para los singletons, por ejemplo None
, donde no le importan los objetos que podrían pretender ser None
o donde desea protegerse contra los objetos que se rompen cuando se los compara None
.
None
tiene pocos métodos y casi no tiene atributos. Si su __eq__
prueba esperaba un método o atributo, podría romperse. def __eq__( self, other ): return self.size == other.size
. Por ejemplo, se romperá si other
resulta ser None
.
is
es como el de Java ==
. Python ==
es como el de Java .equals()
. Por supuesto, esto solo ayuda si conoces Java.
is
es como ===
(muy igual), y por el contrario is not
es como !==
(no exactamente igual).
is not
un solo operador o simplemente está negando el resultado de ser is
interno not foo is bar
?
Primero, déjenme repasar algunos términos. Si solo desea que su pregunta sea respondida, desplácese hacia abajo hasta "Responder su pregunta".
Identidad del objeto : cuando crea un objeto, puede asignarlo a una variable. Entonces también puede asignarlo a otra variable. Y otro.
>>> button = Button()
>>> cancel = button
>>> close = button
>>> dismiss = button
>>> print(cancel is close)
True
En este caso, cancel
, close
, y dismiss
todos se refieren al mismo objeto en la memoria. Solo creó un Button
objeto, y las tres variables se refieren a este objeto. Decimos eso cancel
, close
y dismiss
todos se refieren a objetos idénticos ; es decir, se refieren a un solo objeto.
Igualdad de objeto : cuando compara dos objetos, generalmente no le importa que se refiera exactamente al mismo objeto en la memoria. Con la igualdad de objetos, puede definir sus 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 a
para que pueda usar su propia lógica de comparación.
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 nuevas en la memoria.
Aquí, tengo dos cadenas unicode, a
y b
. Tienen exactamente el mismo contenido, pero no son el mismo objeto en la memoria. Sin embargo, cuando los comparamos, queremos que se comparen igual. 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 unicode
definitivamente 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 del 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 a
y 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 se comparen igual. 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
Al comparar con None
, siempre use is not
. Ninguno es un singleton en Python; solo hay una instancia de este en la memoria.
Al comparar la identidad , esto se puede realizar muy rápidamente. Python comprueba si el objeto al que se refiere tiene la misma dirección de memoria que el objeto Ninguno global: 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 lo hace, examina cada superclase buscando un __eq__
método. Si encuentra uno, Python lo llama. Esto es especialmente malo si el __eq__
método es lento y no regresa de inmediato cuando se da cuenta de que el otro objeto lo es None
.
¿No lo implementaste __eq__
? Entonces, Python probablemente encontrará el __eq__
método object
y lo usará en su lugar, que de todos modos solo verifica la identidad del objeto.
Al comparar la mayoría de las otras cosas en Python, lo usará !=
.
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)
None
es un singleton, por lo tanto, la comparación de identidad siempre funcionará, mientras que un objeto puede falsificar la comparación de igualdad a través de .__eq__()
.
None
, pero un comportamiento incorrecto None
podría ocurrir como un efecto secundario de la implementación de la igualdad contra otros tipos. No son tanto las implicaciones de seguridad como las implicaciones de corrección.
>>> () es () Cierto >>> 1 es 1 Cierto >>> (1,) == (1,) Cierto >>> (1,) es (1,) Falso >>> a = (1,) >>> b = a >>> a es b Cierto
Algunos objetos son singletons y, por lo tanto, is
con ellos es equivalente a ==
. La mayoría no lo son.
()
y 1
no son inherentemente solteros.
-NSMALLNEGINTS <= n <= NSMALLPOSINTS
) y las tuplas vacías son singletons. De hecho, no está documentado ni garantizado, pero es poco probable que cambie.