2010-09-05 21 views
10

Me di cuenta de que puedo usar el operador == para comparar todos los tipos de datos nativos (enteros, cadenas, booleanos, números de coma flotante, etc.) y también listas, tuplas, conjuntos y diccionarios que contienen tipos de datos nativos. En estos casos, el operador == comprueba si dos objetos son iguales. Sin embargo, en algunos otros casos (se trata de comparar instancias de clases que he creado) el operador == simplemente comprueba si hacen referencia a las dos variables del mismo objeto (lo que en estos casos el operador == es equivalente al operador is)¿Cuándo el operador `==` no es equivalente al operador `is`? (Python)

Mi pregunta es: ¿Cuándo el operador == hace más que solo comparar identidades?

EDIT: Estoy usando Python 3

+1

Esencialmente, '' == es diferente de 'is', siempre que sea una clase anula el método' __eq__' que hereda de 'object', por lo que no hay una respuesta fácil esta pregunta. Dependiendo de la versión de Python que esté utilizando, las cosas se complican aún más debido a la existencia de '__cmp__'. Además de la curiosidad, ¿hay alguna razón práctica para la pregunta? – Dirk

+0

@Dirk, gracias. Lo pido principalmente por curiosidad, pero también creo que es bueno saber cuándo puedo usar exactamente el operador == para verificar la igualdad de los objetos. – snakile

Respuesta

19

En Python, el operador == se implementa en términos de la magic method __eq__, que por defecto se implementa mediante la comparación de identidad. Sin embargo, puede anular el método para proporcionar su propio concepto de igualdad de objetos. Tenga en cuenta que, si lo hace, también anulará al menos __ne__ (que implementa el operador !=) y __hash__, que calcula un código hash para la instancia.

Me pareció muy útil, incluso en Python, para hacer mis __eq__ implementaciones cumplen con las normas establecidas en el lenguaje Java para las implementaciones del método equals, a saber:

  • Es reflexiva: para cualquier el valor de referencia no nulo x, x.equals (x) debería devolver verdadero.
  • Es simétrico: para cualquier valor de referencia no nulo x e y, x.equals (y) debería devolver verdadero si y solo si y.equals (x) devuelve verdadero.
  • Es transitivo: para cualquier valor de referencia no nulo x, y y z, si x.equals (y) devuelve verdadero y y.equals (z) devuelve verdadero, entonces x.equals (z) debe devolver verdadero .
  • Es coherente: para cualquier valor de referencia no nulo xey, las invocaciones múltiples de x.equals (y) devuelven true o devuelven false de manera consistente siempre que no se modifique la información utilizada en comparaciones iguales en los objetos.
  • Para cualquier valor de referencia no nulo x, x.equals (nulo) debe devolver falso.

el último debe reemplazarse la null con None, pero las reglas no son tan fácil aquí en Python como en Java.

+0

Gracias por el conjunto de reglas para implementar '__eq__' – snakile

+3

Estas "reglas" tienen una fuerte raíz matemática: http://en.wikipedia.org/wiki/Equivalence_relation –

+1

díselo a javascript -> http://stackoverflow.com/questions/1995113/strangest-language-feature/1998224 # 1998224 – wim

16

== y is siempre son conceptualmente distintos: los delegados anteriores al objeto __eq__ [1] del lado izquierdo, este último siempre comprueba la identidad, sin ninguna delegación. Lo que parece confundirlo es que object.__eq__ (que se hereda de forma predeterminada por las clases codificadas por el usuario que no lo anulan, ¡por supuesto!) Se implementa en términos de identidad (después de todo, un object desnudo tiene absolutamente nada marque excepto su identidad, entonces ¿qué otra cosa podría hacer?! -).

[1] omitiendo por simplicidad el concepto heredado del método __cmp__, que es solo una complicación marginal y no cambia nada importante en la esencia del párrafo ;-).

4

Lo que es tal vez más importante punto es que la recomendación es usar siempre:

if myvalue is None: 
no

if myvalue == None: 

Y no volver a utilizar:

if myvalue is True: 

pero el uso:

if myvalue: 

Este último punto no es tan claro para mí, ya que creo que hay veces para separar el booleano True de otros valores verdaderos como "Alex Martelli", decir que no es falso en "Alex Martelli" (absolutamente no, incluso aumenta la excepción :)) pero hay '' en "Alex Martelli" (como en cualquier otra cadena).

+0

¿Qué hace que 'if myvalue is None' sea mejor que 'if myvalue == None'? – snakile

+3

Ver PEP8 para la regla. Vea los comentarios de Alex sobre __eq__, adicionalmente es más rápido: http://jaredgrubb.blogspot.com/2009/04/python-is-none-vs-none.html –

7

El == hace más que comparar identidad cuando se trata de ints. No solo comprueba que las dos entradas son el mismo objeto; en realidad asegura que sus valores coincidan. Considere lo siguiente:

>>> x=10000 
>>> y=10000 
>>> x==y,x is y 
(True, False) 
>>> del x 
>>> del y 
>>> x=10000 
>>> y=x 
>>> x==y,x is y 
(True, True) 

La aplicación "estándar" Python hace algunas cosas detrás de las escenas para los pequeños enteros, por lo que cuando se prueba con valores pequeños se puede conseguir algo diferente. Compare esto con el caso equivalente 10000:

>>> del y 
>>> del x 
>>> x=1 
>>> y=1 
>>> x==y,x is y 
(True, True) 
+2

interesante. +1 – snakile

Cuestiones relacionadas