¿Hay alguna diferencia entre "==" y "es"?

630

Mi Google-fu me ha fallado.

En Python, ¿son equivalentes las siguientes dos pruebas de igualdad?

n = 5
# Test one.
if n == 5:
    print 'Yay!'

# Test two.
if n is 5:
    print 'Yay!'

¿Es esto cierto para los objetos en los que compararía instancias (por listejemplo)?

De acuerdo, este tipo de respuestas a mi pregunta:

L = []
L.append(1)
if L == [1]:
    print 'Yay!'
# Holds true, but...

if L is [1]:
    print 'Yay!'
# Doesn't.

Entonces ==, ¿el valor de las pruebas donde las ispruebas para ver si son el mismo objeto?

Bernardo
fuente

Respuestas:

928

isregresará Truesi dos variables apuntan al mismo objeto, ==si los objetos a los que se refieren las variables son iguales.

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

# Make a new copy of list `a` via the slice operator, 
# and assign it to variable `b`
>>> b = a[:] 
>>> b is a
False
>>> b == a
True

En su caso, la segunda prueba solo funciona porque Python almacena en caché objetos enteros pequeños, que es un detalle de implementación. Para enteros más grandes, esto no funciona:

>>> 1000 is 10**3
False
>>> 1000 == 10**3
True

Lo mismo es cierto para los literales de cadena:

>>> "a" is "a"
True
>>> "aa" is "a" * 2
True
>>> x = "a"
>>> "aa" is x * 2
False
>>> "aa" is intern(x*2)
True

Por favor vea esta pregunta también.

Torsten Marek
fuente
2
He descubierto que: echo 'import sys;tt=sys.argv[1];print(tt is "foo", tt == "foo", id(tt)==id("foo"))'| python3 - foosalida: False True False.
ahuigo
Me perdiste con la b = a[:]parte de copia de la lista del operador de división, así que edité tu respuesta para tener un comentario allí. Parece que acabo de llegar al umbral para no tener que revisar mis ediciones antes de que se apliquen, así que espero que sea genial para ti. De todos modos, aquí hay una referencia útil sobre cómo copiar listas que encontré y tuve que hacer referencia para averiguar qué estaba haciendo: stackoverflow.com/a/2612815/4561887
Gabriel Staples
Otra forma de demostrar la diferencia es mediante la comparación de objetos de diferentes tipos, que, por supuesto, nunca pueden ser el mismo objeto, pero pueden ser iguales cuando se usan ==. Entonces, 5.0por ejemplo, es un valor de coma flotante, mientras que 5es un número entero. Pero 5.0 == 5aún regresará Trueporque representan el mismo valor. En términos de rendimiento y tipificación de pato, isel intérprete siempre prueba al comparar las direcciones de memoria del operando, mientras ==que depende del objeto decidir si se define como igual a otra cosa.
Bachsau
3
1000 is 10**3se evalúa como Verdadero en Python 3.7 ya que 10 ** 3 es tipo int. Pero se 1000 is 1e3evalúa como False ya que 1e3 es type float.
Ahmed Fasih
@AhmedFasih Si la 1000 is 10**3verdad es o no depende de la implementación y depende de que el compilador evalúe previamente la expresión 10**3. x=10; 1000 is x**3evalúa a False.
Chepner
314

Hay una regla general simple que le indica cuándo usar ==o is.

  • ==es por la igualdad de valores . Úselo cuando desee saber si dos objetos tienen el mismo valor.
  • ises para referencia de igualdad . Úselo cuando desee saber si dos referencias se refieren al mismo objeto.

En general, cuando compara algo con un tipo simple, generalmente verifica la igualdad de valor , por lo que debe usar ==. Por ejemplo, la intención de su ejemplo es probablemente verificar si x tiene un valor igual a 2 ( ==), no si xse refiere literalmente al mismo objeto que 2.


Algo más a tener en cuenta: debido a la forma en que funciona la implementación de referencia de CPython, obtendrá resultados inesperados e inconsistentes si usa por error ispara comparar la igualdad de referencia en enteros:

>>> a = 500
>>> b = 500
>>> a == b
True
>>> a is b
False

Eso es más o menos lo que esperábamos: ay btienen el mismo valor, pero son entidades distintas. ¿Pero qué hay de esto?

>>> c = 200
>>> d = 200
>>> c == d
True
>>> c is d
True

Esto es inconsistente con el resultado anterior. ¿Que está pasando aqui? Resulta que la implementación de referencia de Python almacena en caché objetos enteros en el rango -5..256 como instancias singleton por razones de rendimiento. Aquí hay un ejemplo que demuestra esto:

>>> for i in range(250, 260): a = i; print "%i: %s" % (i, a is int(str(i)));
... 
250: True
251: True
252: True
253: True
254: True
255: True
256: True
257: False
258: False
259: False

Esta es otra razón obvia para no usar is: el comportamiento se deja a las implementaciones cuando se usa erróneamente para la igualdad de valores.

John Feminella
fuente
Con respecto al primer ejemplo de a=500y b=500, solo quería señalar que si establece ay bun número entero entre [-5, 256], en a is brealidad regresa True. Más información aquí: stackoverflow.com/q/306313/7571052
AsheKetchum
1
@AsheKetchum, sí, tenga en cuenta que escribí "Resulta que la implementación de referencia de Python almacena en caché objetos enteros en el rango -5..256 como instancias singleton por razones de rendimiento".
John Feminella
34

==determina si los valores son iguales, mientras que isdetermina si son exactamente el mismo objeto.

stephenbayer
fuente
32

¿Hay alguna diferencia entre ==y isen Python?

Sí, tienen una diferencia muy importante.

==: verifique la igualdad: la semántica es que los objetos equivalentes (que no son necesariamente el mismo objeto) probarán como iguales. Como dice la documentación :

Los operadores <,>, ==,> =, <=, y! = Comparan los valores de dos objetos.

is: verifique la identidad: la semántica es que el objeto (como se mantiene en la memoria) es el objeto. De nuevo, la documentación dice :

Los operadores isy la is notprueba de identidad del objeto: x is yes verdadero si y solo si xy yson el mismo objeto. La identidad del objeto se determina utilizando la id()función. x is not yproduce el valor de verdad inverso.

Por lo tanto, verificar la identidad es lo mismo que verificar la igualdad de las ID de los objetos. Es decir,

a is b

es lo mismo que:

id(a) == id(b)

¿Dónde idestá la función incorporada que devuelve un número entero que "se garantiza que es único entre los objetos existentes simultáneamente" (ver help(id)) y dónde ay bcualquier objeto arbitrario.

Otras direcciones de uso

Debe usar estas comparaciones para su semántica. Use ispara verificar la identidad y ==para verificar la igualdad.

Entonces, en general, usamos ispara verificar la identidad. Esto suele ser útil cuando buscamos un objeto que solo debería existir una vez en la memoria, denominado "singleton" en la documentación.

Los casos de uso para isincluyen:

  • None
  • valores de enumeración (cuando se utilizan enumeraciones del módulo de enumeración)
  • generalmente módulos
  • generalmente objetos de clase resultantes de definiciones de clase
  • generalmente objetos de función resultantes de definiciones de funciones
  • cualquier otra cosa que solo debería existir una vez en la memoria (todos los singletons, generalmente)
  • un objeto específico que desea por identidad

Los casos de uso habituales para ==incluyen:

  • números, incluyendo enteros
  • instrumentos de cuerda
  • liza
  • conjuntos
  • diccionarios
  • objetos mutables personalizados
  • otros objetos inmutables incorporados, en la mayoría de los casos

El caso de uso general, nuevamente, para ==, es que el objeto que desea puede no ser el mismo objeto, sino que puede ser uno equivalente

PEP 8 direcciones

PEP 8, la guía de estilo oficial de Python para la biblioteca estándar también menciona dos casos de uso parais :

Las comparaciones con singletons como Nonesiempre deben hacerse con iso is not, nunca con los operadores de igualdad.

Además, tenga cuidado al escribir if xcuando realmente quiere decir if x is not None, por ejemplo, al probar si una variable o argumento predeterminado None se estableció en algún otro valor. ¡El otro valor podría tener un tipo (como un contenedor) que podría ser falso en un contexto booleano!

Inferir igualdad de identidad

Si ises cierto, la igualdad generalmente se puede inferir: lógicamente, si un objeto es él mismo, entonces debería probarse como equivalente a sí mismo.

En la mayoría de los casos, esta lógica es cierta, pero se basa en la implementación del __eq__método especial. Como dicen los documentos ,

El comportamiento predeterminado para la comparación de igualdad ( ==y !=) se basa en la identidad de los objetos. Por lo tanto, la comparación de igualdad de instancias con la misma identidad resulta en igualdad, y la comparación de igualdad de instancias con identidades diferentes resulta en desigualdad. Una motivación para este comportamiento predeterminado es el deseo de que todos los objetos sean reflexivos (es decir, x es y implica x == y).

y en aras de la coherencia, recomienda:

La comparación de igualdad debe ser reflexiva. En otras palabras, los objetos idénticos deben comparar iguales:

x is y implica x == y

Podemos ver que este es el comportamiento predeterminado para los objetos personalizados:

>>> class Object(object): pass
>>> obj = Object()
>>> obj2 = Object()
>>> obj == obj, obj is obj
(True, True)
>>> obj == obj2, obj is obj2
(False, False)

El contrapositivo también suele ser cierto: si algo prueba que no es igual, generalmente se puede inferir que no son el mismo objeto.

Dado que las pruebas de igualdad se pueden personalizar, esta inferencia no siempre es válida para todos los tipos.

Una excepción

Una excepción notable es nan: siempre prueba que no es igual a sí mismo:

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

Verificar la identidad puede ser una verificación mucho más rápida que verificar la igualdad (lo que puede requerir la verificación recursiva de los miembros).

Pero no puede ser sustituido por igualdad donde puede encontrar más de un objeto como equivalente.

Tenga en cuenta que al comparar la igualdad de listas y tuplas se supondrá que la identidad de los objetos es igual (porque esta es una comprobación rápida). Esto puede crear contradicciones si la lógica es inconsistente, como lo es para nan:

>>> [nan] == [nan]
True
>>> (nan,) == (nan,)
True

Un cuento de precaución:

La pregunta está intentando usar ispara comparar enteros. No debe suponer que una instancia de un entero es la misma instancia que una obtenida por otra referencia. Esta historia explica por qué.

Un comentarista tenía un código que se basaba en el hecho de que los enteros pequeños (-5 a 256 inclusive) son singletons en Python, en lugar de verificar la igualdad.

Wow, esto puede conducir a algunos errores insidiosos. Tenía un código que verificaba si a es b, que funcionó como quería porque a y b suelen ser números pequeños. El error solo ocurrió hoy, después de seis meses de producción, porque a y b finalmente fueron lo suficientemente grandes como para no ser almacenados en caché. - gwg

Funcionó en desarrollo. Puede haber pasado algunas pruebas unitarias.

Y funcionó en producción, hasta que el código verificó un número entero mayor que 256, momento en el cual falló en producción.

Esta es una falla de producción que podría haberse detectado en la revisión del código o posiblemente con un verificador de estilo.

Permítanme enfatizar: no lo use ispara comparar enteros.

Aaron Hall
fuente
"no usar es en absoluto" sería una buena regla también. La idiomática is Nonees una excepción, pero eso == Nonetambién funciona ...
Jean-François Fabre
@ Jean-FrançoisFabre Otra excepción: la documentación oficial parece recomendar el uso ispara comparar Enums.
Arthur
@ Arthur He agregado una lista de casos de uso ...
Aaron Hall
19

¿Cuál es la diferencia entre isy ==?

==y isson diferentes comparaciones! Como otros ya dijeron:

  • == compara los valores de los objetos.
  • is compara las referencias de los objetos.

En Python los nombres se refieren a objetos, por ejemplo en este caso value1y se value2refieren a una intinstancia que almacena el valor 1000:

value1 = 1000
value2 = value1

ingrese la descripción de la imagen aquí

Porque se value2refiere al mismo objeto isy ==dará True:

>>> value1 == value2
True
>>> value1 is value2
True

En el siguiente ejemplo, los nombres value1y se value2refieren a diferentes intinstancias, incluso si ambos almacenan el mismo número entero:

>>> value1 = 1000
>>> value2 = 1000

ingrese la descripción de la imagen aquí

Debido a que el mismo valor (entero) se almacena ==será True, por eso a menudo se denomina "valor de comparación". Sin embargo is, regresará Falseporque estos son objetos diferentes:

>>> value1 == value2
True
>>> value1 is value2
False

¿Cuándo usar cuál?

Generalmente ises una comparación mucho más rápida. Es por eso que CPython almacena en caché (o quizás reutilizaciones sería el mejor término) ciertos objetos como enteros pequeños, algunas cadenas, etc. Pero esto debe tratarse como un detalle de implementación que podría (incluso si es poco probable) cambiar en cualquier momento sin previo aviso.

Solo debe usaris si usted:

  • desea verificar si dos objetos son realmente el mismo objeto (no solo el mismo "valor"). Un ejemplo puede ser si se utiliza un objeto Singleton como constante.
  • desea comparar un valor con una constante de Python . Las constantes en Python son:

    • None
    • True1
    • False1
    • NotImplemented
    • Ellipsis
    • __debug__
    • clases (por ejemplo int is into int is float)
    • podría haber constantes adicionales en módulos integrados o módulos de terceros. Por ejemplo np.ma.maskeddel módulo NumPy)

En cualquier otro caso, debe usar== para verificar la igualdad.

¿Puedo personalizar el comportamiento?

Hay algún aspecto ==que no se ha mencionado ya en las otras respuestas: es parte del "modelo de datos" de Pythons . Eso significa que su comportamiento se puede personalizar utilizando el __eq__método. Por ejemplo:

class MyClass(object):
    def __init__(self, val):
        self._value = val

    def __eq__(self, other):
        print('__eq__ method called')
        try:
            return self._value == other._value
        except AttributeError:
            raise TypeError('Cannot compare {0} to objects of type {1}'
                            .format(type(self), type(other)))

Este es solo un ejemplo artificial para ilustrar que el método realmente se llama:

>>> MyClass(10) == MyClass(10)
__eq__ method called
True

Tenga en cuenta que por defecto (si no __eq__se puede encontrar otra implementación de la clase o las superclases) __eq__utiliza is:

class AClass(object):
    def __init__(self, value):
        self._value = value

>>> a = AClass(10)
>>> b = AClass(10)
>>> a == b
False
>>> a == a

Por lo tanto, es importante implementarlo __eq__si desea "más" que solo una comparación de referencia para clases personalizadas.

Por otro lado, no puede personalizar los ischeques. Siempre se comparará solo si tiene la misma referencia.

¿Estas comparaciones siempre devolverán un valor booleano?

Debido a que __eq__se puede volver a implementar o anular, no se limita a return Trueo False. Se podría devolver nada (pero en la mayoría de los casos se debe devolver un valor lógico!).

Por ejemplo, con matrices NumPy ==, devolverá una matriz:

>>> import numpy as np
>>> np.arange(10) == 2
array([False, False,  True, False, False, False, False, False, False, False], dtype=bool)

¡Pero los ischeques siempre volverán Trueo False!


1 Como Aaron Hall mencionó en los comentarios:

En general, no debe hacer ninguna is Trueo is Falseverificaciones porque normalmente se usan estas "verificaciones" en un contexto que convierte implícitamente la condición a un valor booleano (por ejemplo, en una ifdeclaración). Entonces, hacer la is Truecomparación y el elenco booleano implícito está haciendo más trabajo que solo hacer el elenco booleano, y se limita a los booleanos (que no se considera pitónico).

Como PEP8 menciona:

No compare valores booleanos con Trueo Falseusando ==.

Yes:   if greeting:
No:    if greeting == True:
Worse: if greeting is True:
MSeifert
fuente
2
Voy a tener que estar en desacuerdo con su afirmación para comparar "constantes" con is: los nombres que apuntan a booleanos deben verificarse con un contexto booleano, como if __debug__:o if not __debug__:. Nunca debe hacer if __debug__ is True:o if __debug__ == True:, además, una constante es simplemente un valor semántico constante, no un singleton, por lo tanto, verificar isen ese caso no es semánticamente correcto. Te reto a que encuentres una fuente que respalde tus afirmaciones; no creo que encuentres una.
Aaron Hall
@AaronHall ¿Qué te hace pensar que las constantes no son singletons? Nota que sólo None, True, Falsey __debug__son lo que se llama "valor semántico constante", porque no pueden ser reasignados. Pero todos ellos son solteros.
MSeifert
Lea PEP 8 - Ctrl-F y busque la palabra "peor". - Si estás probando unidades
Aaron Hall
@AaronHall En algunas circunstancias, realmente necesitas el is Trueo if Falsecheck (pero sí, estos son bastante raros, pero si los haces puedes usarlos is). Es por eso que incluso CPython los usa a veces (por ejemplo aquí o aquí )
MSeifert
19

Son completamente diferentes . iscomprueba la identidad del objeto, mientras que ==comprueba la igualdad (una noción que depende de los tipos de los dos operandos).

Es solo una coincidencia afortunada que " is" parece funcionar correctamente con enteros pequeños (por ejemplo, 5 == 4 + 1). Esto se debe a que CPython optimiza el almacenamiento de enteros en el rango (-5 a 256) al hacerlos únicos . Este comportamiento depende totalmente de la implementación y no se garantiza su preservación en todo tipo de operaciones de transformación menores.

Por ejemplo, Python 3.5 también crea cadenas cortas simples, pero cortarlas interrumpe este comportamiento:

>>> "foo" + "bar" == "foobar"
True
>>> "foo" + "bar" is "foobar"
True
>>> "foo"[:] + "bar" == "foobar"
True
>>> "foo"[:] + "bar" is "foobar"
False
Dan Lenski
fuente
10

https://docs.python.org/library/stdtypes.html#comparisons

ispruebas de identidad ==pruebas de igualdad

Cada valor entero (pequeño) se asigna a un solo valor, por lo que cada 3 es idéntico e igual. Este es un detalle de implementación, aunque no forma parte de la especificación del lenguaje

mmaibaum
fuente
6

Tu respuesta es correcta. El isoperador compara la identidad de dos objetos. El ==operador compara los valores de dos objetos.

La identidad de un objeto nunca cambia una vez que se ha creado; puede pensar en ello como la dirección del objeto en la memoria.

Puede controlar el comportamiento de comparación de los valores de los objetos definiendo un __cmp__método o un método de comparación rico como __eq__.

Dave Webb
fuente
3

En pocas palabras, iscomprueba si dos referencias apuntan al mismo objeto o no. ==comprueba si dos objetos tienen el mismo valor o no.

a=[1,2,3]
b=a        #a and b point to the same object
c=list(a)  #c points to different object 

if a==b:
    print('#')   #output:#
if a is b:
    print('##')  #output:## 
if a==c:
    print('###') #output:## 
if a is c:
    print('####') #no output as c and a point to different object 
suvojit_007
fuente
2

Como dijo John Feminella, la mayoría de las veces usará == y! = Porque su objetivo es comparar valores. Solo me gustaría clasificar lo que harías el resto del tiempo:

Hay una única instancia de NoneType, es decir, None es un singleton. En consecuencia foo == Noney foo is Nonesignifica lo mismo. Sin embargo, la isprueba es más rápida y se debe usar la convención Pythonic foo is None.

Si usted está haciendo un poco de introspección o curioseaba con la recolección de basura o la comprobación de si la cadena hecha a la medida internar aparato funciona o cosas por el estilo, entonces es probable que tenga un caso de uso para el fooque es bar.

True y False también son (ahora) singletons, pero no hay un caso de foo == Trueuso ni un caso de uso para foo is True.

John Machin
fuente
2

La mayoría de ellos ya respondieron al punto. Solo como una nota adicional (basada en mi comprensión y experimentación pero no de una fuente documentada), la declaración

== si los objetos a los que se refieren las variables son iguales

de las respuestas anteriores deben leerse como

== si los objetos a los que hacen referencia las variables son iguales y los objetos que pertenecen al mismo tipo / clase

. Llegué a esta conclusión en base a la prueba a continuación:

list1 = [1,2,3,4]
tuple1 = (1,2,3,4)

print(list1)
print(tuple1)
print(id(list1))
print(id(tuple1))

print(list1 == tuple1)
print(list1 is tuple1)

Aquí el contenido de la lista y la tupla son los mismos, pero el tipo / clase es diferente.

Sandeep
fuente
2

La diferencia de Python entre es y es igual (==)

El operador is puede parecer lo mismo que el operador de igualdad, pero no son lo mismo.

El verifica si ambas variables apuntan al mismo objeto, mientras que el signo == verifica si los valores para las dos variables son iguales.

Entonces, si el operador is devuelve True, entonces la igualdad es definitivamente True, pero lo contrario puede o no ser True.

Aquí hay un ejemplo para demostrar la similitud y la diferencia.

>>> a = b = [1,2,3]
>>> c = [1,2,3]
>>> a == b
True
>>> a == c
True
>>> a is b
True
>>> a is c
False
>>> a = [1,2,3]
>>> b = [1,2]
>>> a == b
False
>>> a is b
False
>>> del a[2]
>>> a == b
True
>>> a is b
False
Tip: Avoid using is operator for immutable types such as strings and numbers, the result is unpredictable.
Projesh Bhoumik
fuente
1
Utilice solo comillas en bloque para el texto que citó de otra fuente, momento en el que debe incluir la atribución (consulte stackoverflow.com/help/referencing ). Si este es su propio texto, elimine las comillas en bloque.
Martijn Pieters
0

A medida que las otras personas en esta publicación responden a la pregunta en detalle, enfatizaría principalmente la comparación entre isy == para cadenas que pueden dar diferentes resultados e instaría a los programadores a usarlas cuidadosamente.

Para la comparación de cadenas, asegúrese de usar en ==lugar de is:

str = 'hello'
if (str is 'hello'):
    print ('str is hello')
if (str == 'hello'):
    print ('str == hello')

Fuera:

str is hello
str == hello

Pero en el siguiente ejemplo ==y isobtendremos resultados diferentes:

str = 'hello sam'
    if (str is 'hello sam'):
        print ('str is hello sam')
    if (str == 'hello sam'):
        print ('str == hello sam')

Fuera:

str == hello sam

Conclusión:

Use con iscuidado para comparar entre cadenas

imanzabet
fuente
¿por qué "is" "funciona así para cadenas con espacios?
Akash Gupta
De acuerdo con las respuestas anteriores: Parece que Python realiza el almacenamiento en caché en enteros pequeños y cadenas, lo que significa que utiliza la misma referencia de objeto para las ocurrencias de cadena 'hola' en esta instantánea de código, mientras que no preforma el almacenamiento en caché para 'hola sam' como es relativamente más grande que 'hola' (es decir, maneja diferentes referencias de la cadena 'hola sam', y es por eso que el operador 'es' devuelve falso en el ejemplo posterior) Por favor
corríjame