Python `si x no es Ninguno` o` si no x es Ninguno`?

747

Siempre he pensado que la if not x is Noneversión es más clara, pero la guía de estilo de Google y el PEP-8 los usan if x is not None. ¿Hay alguna diferencia de rendimiento menor (supongo que no), y ¿hay algún caso en el que uno realmente no encaja (haciendo que el otro sea un claro ganador para mi convención)? *

* Me refiero a cualquier singleton, en lugar de solo None.

... para comparar singletons como None. El uso es o no es.

orokusaki
fuente
8
is notes un operador por derecho propio. Al igual !=. Si lo prefiere, not x is Noneentonces también debería preferir not a == bmás a != b.
Tomasz Gandor
@TomaszGandor Ya no tengo esta opinión sobre not x is None(las respuestas aquí me convencieron); sin embargo, vale la pena señalar que not a == bes el estilo preferido en Python en comparación con a != b.
orokusaki
44
@orokusaki es not a == brealmente el estilo preferido? Nunca lo había visto de esa manera y en todas partes que uso la gente lo usa !=.
Mike - SMT
2
@orokusaki en Python legibilidad cuenta lo que es un estilo preferido utilizar un operador !=en lugar de dos operadores not, ==.
Jeyekomon

Respuestas:

995

No hay diferencia de rendimiento, ya que compilan al mismo código de bytes:

Python 2.6.2 (r262:71600, Apr 15 2009, 07:20:39)
>>> import dis
>>> def f(x):
...    return x is not None
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> def g(x):
...   return not x is None
...
>>> dis.dis(g)
  2           0 LOAD_FAST                0 (x)
              3 LOAD_CONST               0 (None)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

Estilísticamente, trato de evitar not x is y. Aunque el compilador siempre lo tratará como not (x is y), un lector humano podría malinterpretar la construcción como (not x) is y. Si escribo, x is not yentonces no hay ambigüedad.

Daniel Stutzbach
fuente
103
A menos que el mismo lector humano pensara que era x is (not y). Pero tiendo a estar de acuerdo contigo para tu otro razonamiento.
Etaoin
24
adicionalmente "no es" es menos ambiguo en este contexto "si a no es Ninguno yb es Ninguno:" vs "si no es Ninguno yb es Ninguno:"
Gordon Wrigley
45
el operador debe estar "aint"
bean
217

La guía de estilo de Google y Python es la mejor práctica:

if x is not None:
    # Do something about x

El uso not xpuede causar resultados no deseados.

Vea abajo:

>>> x = 1
>>> not x
False
>>> x = [1]
>>> not x
False
>>> x = 0
>>> not x
True
>>> x = [0]         # You don't want to fall in this one.
>>> not x
False

Puede que le interesen para ver qué literales son evaluados para Trueo Falseen Python:


Editar para comentar a continuación:

Acabo de hacer algunas pruebas más. not x is Noneno niega xprimero y luego se compara con None. De hecho, parece que el isoperador tiene una mayor prioridad cuando se usa de esa manera:

>>> x
[0]
>>> not x is None
True
>>> not (x is None)
True
>>> (not x) is None
False

Por lo tanto, not x is Nonees, en mi sincera opinión, mejor evitarlo.


Más edición:

Acabo de hacer más pruebas y puedo confirmar que el comentario de bukzor es correcto. (Al menos, no pude demostrarlo de otra manera).

Esto significa que if x is not Nonetiene el resultado exacto como if not x is None. Estoy corregido. Gracias bukzor

Sin embargo, mi respuesta sigue en pie: use lo convencionalif x is not None .:]

Xavier Ho
fuente
131

El código debe escribirse para que el programador lo entienda primero y luego el compilador o el intérprete. La construcción "no es" se parece más al inglés que "no es".

Mark Ransom
fuente
33

Python if x is not Noneo if not x is None?

TLDR: el compilador de bytecode los analiza a ambos, por x is not Nonelo que, por razones de legibilidad, úselos if x is not None.

Legibilidad

Usamos Python porque valoramos cosas como la legibilidad humana, la usabilidad y la corrección de varios paradigmas de programación sobre el rendimiento.

Python optimiza la legibilidad, especialmente en este contexto.

Analizar y compilar el código de bytes

Se not une más débilmente que is, por lo que no hay diferencia lógica aquí. Ver la documentación :

Los operadores isy la is notprueba de identidad del objeto: x is yes verdadero si y solo si x e y son el mismo objeto. x is not yproduce el valor de verdad inverso.

El is notse proporciona específicamente en la gramática de Python como una mejora de legibilidad para el lenguaje:

comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'

Y, por lo tanto, también es un elemento unitario de la gramática.

Por supuesto, no se analiza igual:

>>> import ast
>>> ast.dump(ast.parse('x is not None').body[0].value)
"Compare(left=Name(id='x', ctx=Load()), ops=[IsNot()], comparators=[Name(id='None', ctx=Load())])"
>>> ast.dump(ast.parse('not x is None').body[0].value)
"UnaryOp(op=Not(), operand=Compare(left=Name(id='x', ctx=Load()), ops=[Is()], comparators=[Name(id='None', ctx=Load())]))"

Pero entonces el compilador de bytes realmente traducirá el not ... isa is not:

>>> import dis
>>> dis.dis(lambda x, y: x is not y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE
>>> dis.dis(lambda x, y: not x is y)
  1           0 LOAD_FAST                0 (x)
              3 LOAD_FAST                1 (y)
              6 COMPARE_OP               9 (is not)
              9 RETURN_VALUE

Entonces, en aras de la legibilidad y el uso del lenguaje como estaba previsto, utilícelo is not.

No usarlo no es sabio.

Aaron Hall
fuente
"Se notune más débilmente que is, por lo que no hay diferencia lógica aquí", excepto que Python no tiene que imponer identidades lógicas y algebraicas para mantener (no hay razón intrínseca para (1 + 2)*3evaluar lo mismo 1*3 + 2*3). Aquí aparentemente Python está engañando y optimizando UNARY_NOT.
Alexey
30

La respuesta es más simple de lo que la gente lo hace.

No hay ventaja técnica de ninguna manera, y "x no es y" es lo que todos los demás usan , lo que lo convierte en el claro ganador. No importa que "se parezca más al inglés" o no; todos lo usan, lo que significa que todos los usuarios de Python, incluso los usuarios chinos, cuyo lenguaje Python no se parece en nada, lo entenderán de un vistazo, donde la sintaxis un poco menos común tomará un par de ciclos cerebrales adicionales para analizar.

No seas diferente solo por el hecho de ser diferente, al menos en este campo.

Glenn Maynard
fuente
11

Se is notprefiere al operador antes que negar el resultado ispor razones estilísticas. " if x is not None:" se lee igual que el inglés, pero " if not x is None:" requiere la comprensión de la precedencia del operador y no se lee como el inglés.

Si hay una diferencia en el rendimiento, mi dinero está en is notjuego, pero esto casi seguramente no es la motivación para la decisión de preferir esa técnica. Obviamente dependería de la implementación. Como isno se puede anular, de todos modos debería ser fácil optimizar cualquier distinción.

Mike Graham
fuente
9

Personalmente, yo uso

if not (x is None):

lo cual es entendido inmediatamente sin ambigüedad por todos los programadores, incluso aquellos que no son expertos en la sintaxis de Python.

MikeTeX
fuente
55
Un argumento justo con el que estoy de acuerdo, pero creo que el argumento de seguir un estilo idiomático es más fuerte.
clacke
2

if not x is Nonees más similar a otros lenguajes de programación, pero if x is not Nonedefinitivamente me parece más claro (y es más gramaticalmente correcto en inglés).

Dicho esto, parece que es más una preferencia para mí.

Davy8
fuente
0

Preferiría la forma más legible x is not y de lo que pensaría cómo eventualmente escribir la precedencia de manejo de código de los operadores para producir un código mucho más legible.

stefanogreg
fuente