¿Por qué la comparación de cadenas usando ‘==’ o ‘es’ produce a veces un resultado diferente?

Tengo un progtwig de Python en el que dos variables se configuran con el valor 'public' . En una expresión condicional tengo la comparación var1 is var2 que falla, pero si la cambio a var1 == var2 , devuelve True .

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

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

¿Que me estoy perdiendo aqui?

is prueba de identidad, == prueba de igualdad. Lo que sucede en su código se emularía en el intérprete de esta manera:

 >>> 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 el id(a) == id(b)

Otras respuestas aquí son correctas: is usa para comparación de identidad , mientras que == se usa para comparación de igualdad . Ya que lo que te importa es la igualdad (las dos cadenas deben contener los mismos caracteres), en este caso, el operador es simplemente incorrecto y deberías usar == lugar.

El motivo por el is funciona de forma interactiva es que (la mayoría) de los literales de cadena están internados de forma predeterminada. De Wikipedia:

Las cadenas internas aceleran las comparaciones de cadenas, que a veces son un cuello de botella en el rendimiento de las aplicaciones (como comstackdores y tiempos de ejecución del lenguaje de progtwigción dynamic) que dependen en gran medida de tablas hash con claves de cadenas. Sin internarse, verificar que dos cadenas diferentes sean iguales implica examinar cada carácter de ambas cadenas. Esto es lento por varias razones: es inherentemente O (n) en la longitud de las cuerdas; por lo general, requiere lecturas de varias regiones de la memoria, lo que lleva tiempo; y las lecturas llenan el caché del procesador, lo que significa que hay menos caché disponible para otras necesidades. Con cadenas internadas, una simple prueba de identidad de objeto es suficiente después de la operación interna original; esto se implementa normalmente como una prueba de igualdad de puntero, normalmente solo una instrucción de máquina sin ninguna referencia de memoria.

Entonces, cuando tiene dos literales de cadena (palabras que se escriben literalmente en el código fuente de su progtwig, entre comillas) en su progtwig que tienen el mismo valor, el comstackdor de Python internará automáticamente las cadenas, haciendo que ambas se almacenen al mismo tiempo. ubicación de la memoria. (Tenga en cuenta que esto no siempre sucede, y las reglas para cuando esto sucede son bastante complicadas, así que no confíe en este comportamiento en el código de producción).

Dado que en su sesión interactiva, ambas cadenas se almacenan en la misma ubicación de memoria, tienen la misma identidad , por lo que el operador funciona como se esperaba. Pero si construye 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 es la misma cadena , es decir, tiene una identidad diferente, porque es Almacenado en un lugar diferente en la memoria.

La palabra clave is es una prueba para la identidad del objeto, mientras que == es una comparación de valores.

Si usa 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.

Una última cosa a tener en cuenta, puede usar la función interna para asegurarse de que está obteniendo 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 tiene algún tipo de requisito extraño que usar.

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.

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

Digamos que tienes un objeto person simple. 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.

Esta es una nota al margen, pero en python idiomático, a menudo verá cosas como:

 if x is None: # some clauses 

Esto es seguro, porque se garantiza que hay una instancia del objeto nulo (es decir, ninguna) .

Si no estás seguro de lo que estás haciendo, usa ‘==’. Si tiene un poco más de conocimiento al respecto, puede usar ‘is’ para objetos conocidos como ‘Ninguno’.

De lo contrario, terminará preguntándose 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 sigan igual entre las diferentes versiones / implementaciones de python.

Desde mi experiencia limitada con python, is usa para comparar dos objetos para ver si son el mismo objeto en lugar de dos objetos diferentes con el mismo valor. == se utiliza 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.

Creo que tiene que ver con el hecho de que, cuando la comparación ‘is’ se evalúa como falsa, se utilizan dos objetos distintos. Si se evalúa como verdadero, eso significa que internamente está usando el mismo objeto exacto y no creando uno nuevo, posiblemente porque los creó dentro de una fracción de 2 o más segundos y porque no hay una gran diferencia de tiempo entre ellos está optimizado y utiliza el mismo objeto.

Esta es la razón por la que debería utilizar 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 que yo inicialmente no lo asigné a ‘uno’ , si lo hubiera tenido les hubiera hecho el mismo objeto.

Creo que esto se conoce como cadenas “internadas”. Python hace esto, al igual que Java, y también C y C ++ al comstackr en modos optimizados.

Si utiliza dos cadenas idénticas, en lugar de desperdiciar memoria creando dos objetos de cadena, todas las cadenas internadas con el mismo contenido apuntan a la misma memoria.

Esto da como resultado que el operador Python “is” devuelva True porque dos cadenas con el mismo contenido apuntan al mismo objeto de cadena. Esto también sucederá en Java y en C.

Sin embargo, esto solo es útil para ahorrar memoria. No puede confiar en él para probar la igualdad de cadenas, ya que los distintos intérpretes y comstackdores y los motores JIT no siempre pueden hacerlo.

Estoy respondiendo la pregunta aunque la pregunta es demasiado antigua porque ninguna de las respuestas anteriores cita la referencia del idioma

En realidad, el operador verifica la identidad y == el operador verifica la igualdad,

De la referencia de idioma:

Los tipos afectan a casi todos los aspectos del comportamiento del objeto. Incluso la importancia de la identidad del objeto se ve afectada en algún sentido: para los tipos inmutables, las operaciones que computan nuevos valores pueden devolver una referencia a cualquier objeto existente con el mismo tipo y valor, mientras que para los objetos mutables no está permitido . Por ejemplo, después de a = 1; b = 1, ayb pueden o no referirse al mismo objeto con el valor uno, dependiendo de la implementación, pero después de c = []; d = [], c y d están garantizados para referirse a dos listas vacías diferentes, únicas y recién creadas. (Tenga en cuenta que c = d = [] asigna el mismo objeto a c y d).

así que de la statement anterior podemos inferir que las cadenas que son un tipo inmutable pueden fallar cuando se verifican con “es” y pueden ser correctas cuando se marcan con “es”

Lo mismo se aplica para int, tupla que también son tipos inmutables.

La == prueba de operador valor de equivalencia. Python comprueba si el operador comprueba la identidad del objeto, si ambos son realmente el mismo objeto (es decir, viven en la misma dirección en la memoria).

 >>> a = 'banana' >>> b = 'banana' >>> a is b True 

En este ejemplo, Python solo creó un objeto de cadena, y tanto a como b refieren a él. La razón es que Python almacena en caché internamente y reutiliza algunas cadenas como una optimización, en realidad solo hay una cadena ‘banana’ en la memoria, compartida por a y b; Para desencadenar el comportamiento normal, necesita utilizar cadenas más largas:

 >>> a = 'a longer banana' >>> b = 'a longer banana' >>> a == b, a is b (True, False) 

Cuando creas dos listas, obtienes dos objetos:

 >>> a = [1, 2, 3] >>> b = [1, 2, 3] >>> a is b False 

En este caso, diríamos que las dos listas son equivalentes, porque tienen los mismos elementos, pero no son idénticos, porque no son el mismo objeto. Si dos objetos son idénticos, también son equivalentes, pero si son equivalentes, no son necesariamente idénticos.

Si a refiere a un objeto y usted asigna b = a , entonces ambas variables se refieren al mismo objeto:

 >>> a = [1, 2, 3] >>> b = a >>> b is a True 

is prueba de identidad, == prueba de igualdad (consulte la documentación de Python ).

En la mayoría de los casos, si a is b , entonces a == b . Pero hay excepciones, por ejemplo:

 >>> nan = float('nan') >>> nan is nan True >>> nan == nan False 

Por lo tanto, solo se puede usar para pruebas de identidad, nunca pruebas de igualdad.

is va a comparar la ubicación de la memoria. Se utiliza para la comparación a nivel de objeto.

== comparará las variables en el progtwig. Se utiliza para verificar a nivel de valor.

is verificación de equivalencia de nivel de dirección

== comprueba la equivalencia del nivel de valor