Pregunta ¿Por qué la comparación de cadenas en Python usando '==' o 'es' a veces produce un resultado diferente?


Tengo un programa de Python donde dos variables se establecen en el valor 'public'. En una expresión condicional, tengo la comparación var1 is var2 que falla, pero si lo cambio a var1 == var2 vuelve True.

Ahora si abro mi intérprete de Python y hago la misma comparación "es", tiene éxito.

>>> s1 = 'public'
>>> s2 = 'public'
>>> s2 is s1
True

¿Que me estoy perdiendo aqui?


891
2017-10-01 15:40


origen


Respuestas:


is es la prueba de identidad, == es prueba de igualdad. lo que sucede en tu código sería emulado en el intérprete así:

>>> a = 'pub'
>>> b = ''.join(['p', 'u', 'b'])
>>> a == b
True
>>> a is b
False

entonces, no es de extrañar que no sean lo mismo, ¿verdad?

En otras palabras: is es el id(a) == id(b)


1230
2017-10-01 15:45



Otras respuestas aquí son correctas: is se utiliza para identidad comparación, mientras == se utiliza para igualdad comparación. Dado que lo que te importa es la igualdad (las dos cadenas deben contener los mismos caracteres), en este caso el is el operador simplemente está equivocado y deberías estar usando == en lugar.

La razón is funciona de manera interactiva es que (la mayoría) de los literales de cadena son internado por defecto. De la Wikipedia:

Las cadenas internas aceleran la cadena   comparaciones, que a veces son un   cuello de botella de rendimiento en aplicaciones   (como compiladores y dinámica   tiempos de ejecución del lenguaje de programación) que   confiar mucho en tablas hash con   llaves de cadena Sin internado,   comprobando que dos cadenas diferentes   son iguales implica examinar cada   carácter de ambas cadenas. Esto es   lento por varias razones: es   inherentemente O (n) en la longitud del   instrumentos de cuerda; por lo general requiere lecturas   de varias regiones de la memoria, que   tomar tiempo; y las lecturas llenan el   caché del procesador, lo que significa que hay menos   caché disponible para otras necesidades. Con   cadenas internas, un objeto simple   prueba de identidad es suficiente después de la   operación de pasante original; esto es   típicamente implementado como un puntero   prueba de igualdad, normalmente solo una sola   instrucción de la máquina sin memoria   referencia en absoluto.

Por lo tanto, cuando tiene dos literales de cadena (palabras literalmente ingresadas en el código fuente de su programa, rodeado de comillas) en su programa que tienen el mismo valor, el compilador de Python intercalará automáticamente las cadenas, haciendo que ambas se almacenen al mismo ubicación de la memoria (Tenga en cuenta que esto no siempre Sucede, y las reglas para cuando esto sucede son bastante intrincadas, ¡así que por favor no confíe en este comportamiento en el código de producción!)

Dado que en su sesión interactiva ambas cadenas se almacenan realmente en la misma ubicación de memoria, tienen el mismo identidad, entonces el is el operador funciona como se espera Pero si construyes una cadena por algún otro método (incluso si esa cadena contiene exactamente los mismos caracteres), entonces la cadena puede ser igual, pero no lo es la misma cadena - es decir, tiene una diferente identidad, porque está almacenado en un lugar diferente en la memoria.


440
2017-10-01 16:02



los ispalabra clave es una prueba de identidad de objeto mientras == es una comparación de valores

Si utiliza is, el resultado será verdadero si y solo si el objeto es el mismo objeto. Sin embargo, == será verdadero cada vez que los valores del objeto sean los mismos.


94
2017-10-01 15:45



Una última cosa a tener en cuenta es que puede usar la función de interno para asegurarse de obtener una referencia a la misma cadena:

>>> a = intern('a')
>>> a2 = intern('a')
>>> a is a2
True

Como se señaló anteriormente, lo que probablemente no debería hacer es determinar la igualdad en las cadenas. Pero esto puede ser útil para saber si tienes algún tipo de requisito extraño para usar is.

Tenga en cuenta que la función interna pasó de ser una función incorporada a estar en el módulo sys para Python 3.


48
2017-10-01 16:04



is es la prueba de identidad, == es prueba de igualdad. Lo que esto significa es que is es una forma de verificar si dos cosas son las mismo cosas, o simplemente equivalente.

Digamos que tienes un simple person objeto. Si se llama 'Jack' y tiene '23' años, es equivalente a otro Jack de 23 años, pero no es la misma persona.

class Person(object):
   def __init__(self, name, age):
       self.name = name
       self.age = age

   def __eq__(self, other):
       return self.name == other.name and self.age == other.age

jack1 = Person('Jack', 23)
jack2 = Person('Jack', 23)

jack1 == jack2 #True
jack1 is jack2 #False

Tienen la misma edad, pero no son la misma instancia de persona. Una cadena puede ser equivalente a otra, pero no es el mismo objeto.


28
2018-04-29 00:56



Esta es una nota al margen, pero en pitón idiomática, a menudo verá cosas como:

if x is None: 
    # some clauses

Esto es seguro, porque se garantiza que habrá una instancia del objeto nulo (es decir, ninguno).


27
2017-10-01 18:51



Si no está seguro de lo que está haciendo, use '=='. Si tiene un poco más de conocimiento al respecto, puede usar 'es' para objetos conocidos como 'Ninguno'.

De lo contrario, terminarás preguntándote por qué las cosas no funcionan y por qué sucede esto:

>>> a = 1
>>> b = 1
>>> b is a
True
>>> a = 6000
>>> b = 6000
>>> b is a
False

Ni siquiera estoy seguro de si se garantiza que algunas cosas permanezcan igual entre las diferentes versiones / implementaciones de Python.


23
2017-10-01 16:57



Desde mi experiencia limitada con Python, is se usa para comparar dos objetos para ver si son el mismo objeto en lugar de dos objetos diferentes con el mismo valor. == se usa para determinar si los valores son idénticos.

Aquí hay un buen ejemplo:

>>> s1 = u'public'
>>> s2 = 'public'
>>> s1 is s2
False
>>> s1 == s2
True

s1 es una cadena Unicode, y s2 es una cadena normal No son del mismo tipo, pero tienen el mismo valor.


16
2017-10-01 15:48



Creo que tiene que ver con el hecho de que, cuando la comparación 'es' se evalúa como falsa, se usan dos objetos distintos. Si se evalúa como verdadero, significa que internamente está usando el mismo objeto exacto y no crea uno nuevo, posiblemente porque los creó en una fracción de 2 o más segundos y porque no hay una gran brecha de tiempo entre ellos, está optimizado y usa el mismo objeto

Es por eso que deberías estar usando el operador de igualdad ==no is, para comparar el valor de un objeto de cadena.

>>> s = 'one'
>>> s2 = 'two'
>>> s is s2
False
>>> s2 = s2.replace('two', 'one')
>>> s2
'one'
>>> s2 is s
False
>>> 

En este ejemplo, hice s2, que era un objeto de cadena diferente previamente igual a 'uno', pero no es el mismo objeto que s, porque el intérprete no usó el mismo objeto ya que inicialmente no lo asigné a 'uno', si lo tuviera, los habría convertido en el mismo objeto.


12
2017-10-01 15:45