¿Hay alguna diferencia entre "foo is None" y "foo == None"?

217

¿Hay alguna diferencia entre:

if foo is None: pass

y

if foo == None: pass

La convención que he visto en la mayoría del código Python (y el código que yo mismo escribo) es la primera, pero recientemente encontré un código que usa la segunda. None es una instancia (y la única instancia, IIRC) de NoneType, por lo que no debería importar, ¿verdad? ¿Hay alguna circunstancia en la que podría?

Joe Shaw
fuente

Respuestas:

253

issiempre regresa Truesi compara la misma instancia de objeto

Mientras ==que en última instancia se determina por el __eq__()método

es decir


>>> class Foo(object):
       def __eq__(self, other):
           return True

>>> f = Foo()
>>> f == None
True
>>> f is None
False
Brendan
fuente
51
Es posible que desee agregar que None es un singleton, por lo que "None is None" siempre es True.
e-satis el
43
Y es posible que desee agregar que el isoperador no se puede personalizar (sobrecargado por una clase definida por el usuario).
Martineau
@study El método __eq__(self)es un método integrado especial que determina cómo ==se maneja cuando se usa en un objeto Python. Aquí lo hemos anulado para que cuando ==se usa en objetos de tipo Foosiempre devuelva verdadero. No existe un método equivalente para el isoperador, por lo que el comportamiento de isno se puede cambiar de la misma manera.
Brendan
¿Es porque la definición de la clase foo no tiene un constructor, es decir, la función init ?
estudiar el
49

Es posible que desee leer la identidad y equivalencia de este objeto .

La declaración 'es' se usa para la identidad del objeto, verifica si los objetos se refieren a la misma instancia (misma dirección en la memoria).

Y la declaración '==' se refiere a la igualdad (mismo valor).

borrego
fuente
Hmmm, creo que tu enlace cambió, a menos que estés interesado en cómo llamar a funciones externas desde python
Pat
Solo lo intenté a=1;b=1;print(a is b) # True. ¿Alguna idea de por qué a is bresulta ser cierto incluso si parecen ser 2 objetos diferentes (diferentes direcciones en la memoria)?
Johnny Chiu
24

Una palabra de precaución:

if foo:
  # do something

No es exactamente lo mismo que:

if x is not None:
  # do something

La primera es una prueba de valor booleano y se puede evaluar como falsa en diferentes contextos. Hay varias cosas que representan falso en un valor booleano, por ejemplo, contenedores vacíos, valores booleanos. Ninguno también se evalúa como falso en esta situación, pero otras cosas también.

Tendayi Mawushe
fuente
12

(ob1 is ob2) igual a (id(ob1) == id(ob2))

Mykola Kharechko
fuente
66
... pero (ob es ob2) es MUCHO más rápido. Timeit dice que "(a es b)" es 0.0365 usec por ciclo y "(id (a) == id (b))" es 0.153 uso por ciclo. ¡4.2 veces más rápido!
AKX
44
la isversión no necesita una llamada a la función y ninguna búsqueda de atributos del intérprete de python; el intérprete puede responder de inmediato si ob1 es, de hecho, ob2.
u0b34a0f6ae
17
No, no lo hace. {} is {}es falso y id({}) == id({})puede ser (y está en CPython) verdadero. Ver stackoverflow.com/questions/3877230
Piotr Dobrogost el
12

La razón foo is Nonees que la forma preferida es que puede estar manejando un objeto que define el suyo __eq__y que define que el objeto es igual a Ninguno. Por lo tanto, use siempre foo is Nonesi necesita ver si es de hecho None.

truppo
fuente
8

No hay diferencia porque los objetos que son idénticos, por supuesto, serán iguales. Sin embargo, PEP 8 establece claramente que debe usar is:

Las comparaciones con singletons como None siempre deben hacerse con es o no es, nunca los operadores de igualdad.

Thijs van Dien
fuente
7

ispruebas de identidad, no igualdad. Para su declaración foo is none, Python simplemente compara la dirección de memoria de los objetos. Significa que está haciendo la pregunta "¿Tengo dos nombres para el mismo objeto?"

==por otro lado, prueba la igualdad según lo determinado por el __eq__()método. No le importa la identidad.

In [102]: x, y, z = 2, 2, 2.0

In [103]: id(x), id(y), id(z)
Out[103]: (38641984, 38641984, 48420880)

In [104]: x is y
Out[104]: True

In [105]: x == y
Out[105]: True

In [106]: x is z
Out[106]: False

In [107]: x == z
Out[107]: True

Nonees un operador singleton. Entonces None is Nonesiempre es cierto.

In [101]: None is None
Out[101]: True
ChillarAnand
fuente
5

Para Ninguno no debería haber una diferencia entre igualdad (==) e identidad (es). NoneType probablemente devuelve identidad para igualdad. Dado que None es la única instancia que puede hacer de NoneType (creo que esto es cierto), las dos operaciones son las mismas. En el caso de otros tipos, este no es siempre el caso. Por ejemplo:

list1 = [1, 2, 3]
list2 = [1, 2, 3]
if list1==list2: print "Equal"
if list1 is list2: print "Same"

Esto imprimiría "Igual" ya que las listas tienen una operación de comparación que no es la devolución de identidad predeterminada.

Stephen Pellicer
fuente
5

@ Jason :

Recomiendo usar algo más en la línea de

if foo:
    #foo isn't None
else:
    #foo is None

No me gusta usar "if foo:" a menos que foo realmente represente un valor booleano (es decir, 0 o 1). Si foo es una cadena o un objeto u otra cosa, "if foo:" puede funcionar, pero me parece un atajo vago. Si está verificando si x es None, diga "if x is None:".

Graeme Perrow
fuente
La búsqueda de cadenas / listas vacías con "if var" es la forma preferida. La conversión booleana está bien definida y es menos código que incluso funciona mejor. No hay razón para hacer "if len (mylist) == 0" por ejemplo.
truppo
Incorrecto. Supongamos que foo = "". Luego if foodevolverá falso y el comentario #foo is Nonees incorrecto.
blokeley
Nota para los votantes negativos: mi respuesta es citar una respuesta que desde entonces se ha eliminado y no estoy de acuerdo con ella. Si no le gusta el código en mi respuesta, debe votar a favor . :-)
Graeme Perrow
2

Algunos detalles más:

  1. La iscláusula realmente comprueba si los dos objects están en la misma ubicación de memoria o no. es decir, si ambos apuntan a la misma ubicación de memoria y tienen la misma id.

  2. Como consecuencia de 1, isasegura si los dos objects representados léxicamente tienen atributos idénticos (atributos-de-atributos ...) o no.

  3. Creación de instancias de tipos primitivos como bool, int, string(con alguna excepción), NoneTypeque tienen un mismo valor será siempre en la misma posición de memoria.

P.ej

>>> int(1) is int(1)
True
>>> str("abcd") is str("abcd")
True
>>> bool(1) is bool(2)
True
>>> bool(0) is bool(0)
True
>>> bool(0)
False
>>> bool(1)
True

Y dado NoneTypeque solo puede tener una instancia de sí mismo en la tabla de "búsqueda" de Python, por lo tanto, el primero y el segundo son más un estilo de programación del desarrollador que escribió el código (tal vez por coherencia) en lugar de tener alguna razón lógica sutil para elige uno sobre el otro.

Dedos sangrantes
fuente
2
Todos los que lean esto: NO lo utilicen some_string is "bar"para comparar cadenas NUNCA. NO HAY UNA SOLA RAZÓN ACEPTABLE para hacerlo y se ROMPERÁ cuando no lo espere. El hecho de que funcione a menudo es simplemente porque CPython sabe que sería estúpido crear dos objetos inmutables que tengan el mismo contenido. Pero puede suceder no obstante.
ThiefMaster
@ThiefMaster ¿la respuesta tiene la tendencia a ser mal interpretada? Sin embargo, al leerlo nuevamente no pude encontrarlo (con la mención de "algunas excepciones"). Su declaración solo se cumple para cadenas y no int, ¿verdad?
Sangrado dedos
En realidad no, pero como tienes ese ejemplo en tu respuesta, pensé que sería una buena idea advertir a los usuarios que es una mala idea usar eso. Tal vez agregue algo como "# cpython específico / no garantizado" detrás de esa línea ...
ThiefMaster
1

La conclusión de John Machin de que Nonees un singleton es una conclusión respaldada por este código.

>>> x = None
>>> y = None
>>> x == y
True
>>> x is y
True
>>> 

Dado que Nonees un singleton, x == Noney x is Nonetendría el mismo resultado. Sin embargo, en mi opinión estética, x == Nonees lo mejor.

ncmathsadist
fuente
2
No estoy de acuerdo con la opinión al final de esta respuesta. Cuando se compara con ninguno explícitamente, generalmente se pretende que el objeto en cuestión sea exactamente el Noneobjeto. En comparación, rara vez se ve que ninguno se usa en ningún otro contexto, excepto para ser similar a la Falseverdad con otros valores. En esos casos, es más idiomático hacer algo comoif x: pass
SingleNegationElimination
0
a is b # returns true if they a and b are true alias
a == b # returns true if they are true alias or they have values that are deemed equivalence 


a = [1,3,4]
b = a[:] #creating copy of list
a is b # if gives false
False
a == b # gives true
True
Aks
fuente