¿Por qué "no (verdadero) en [falso, verdadero]" devuelve falso?

483

Si hago esto:

>>> False in [False, True]
True

Eso vuelve True. Simplemente porque Falseestá en la lista.

Pero si lo hago:

>>> not(True) in [False, True]
False

Eso vuelve False. Mientras que not(True)es igual a False:

>>> not(True)
False

¿Por qué?

Texom512
fuente
1
stackoverflow
Kasramvd
2
sus paréntesis son confusosnot(True) in [False, True]
Grijesh Chauhan

Respuestas:

730

Operador de precedencia 2.x , 3.x . La precedencia de notes menor que la de in. Entonces es equivalente a:

>>> not ((True) in [False, True])
False

Esto es lo que quieres:

>>> (not True) in [False, True]
True

Como señala @Ben: se recomienda nunca escribir not(True), prefiera not True. El primero hace que parezca una llamada de función, mientras que notes un operador, no una función.

Yu Hao
fuente
279
@ Texom512: También recomendaría nunca escribir not(True); prefieren not True. El primero hace que parezca una llamada a función, que es de donde proviene su confusión; si notera una función, entonces not(True) in ...no podría serlo not ((True) in ...). Debes saber que es un operador (o terminas en situaciones como esta), por lo que debes escribirlo como un operador, no disfrazarlo como una función.
Ben
77
Además, si va a utilizar el espaciado para indicar la precedencia en beneficio del lector, primero asegúrese de tener razón. Probablemente esté bien escribir a + b*c + d, es muy malo escribir a+b * c+d. También not(True)es malo por esa medida también.
Steve Jessop
32
En realidad, nunca escribas not True. Escribe en su Falselugar.
Darkhogg
10
Presumiblemente en la vida real no estaría escribiendo not True, estaría escribiendo algo como not myfunc(x,y,z)dónde myfuncestá alguna función que regresa Trueo False.
Nate CK
3
@ BenC.R.Leggiero Eso es lo que hice en la respuesta original , y otros lo han corregido. La versión actual es lo suficientemente clara para mí, no creo que sea difícil de entender sin los paréntesis redundantes, ya que se ha señalado el problema clave, entender el resto es la habilidad básica de un programador.
Yu Hao
76

not x in y se evalúa como x not in y

Puede ver exactamente lo que está sucediendo desmontando el código. El primer caso funciona como espera:

>>> x = lambda: False in [False, True]
>>> dis.dis(x)
  1           0 LOAD_GLOBAL              0 (False)
              3 LOAD_GLOBAL              0 (False)
              6 LOAD_GLOBAL              1 (True)
              9 BUILD_LIST               2
             12 COMPARE_OP               6 (in)
             15 RETURN_VALUE

El segundo caso, evalúa a True not in [False, True], que es Falseclaramente:

>>> x = lambda: not(True) in [False, True]
>>> dis.dis(x)
  1           0 LOAD_GLOBAL              0 (True)
              3 LOAD_GLOBAL              1 (False)
              6 LOAD_GLOBAL              0 (True)
              9 BUILD_LIST               2
             12 COMPARE_OP               7 (not in)
             15 RETURN_VALUE        
>>> 

En cambio, lo que quería expresar era (not(True)) in [False, True]lo que se esperaba True, y puede ver por qué:

>>> x = lambda: (not(True)) in [False, True]
>>> dis.dis(x)
  1           0 LOAD_GLOBAL              0 (True)
              3 UNARY_NOT           
              4 LOAD_GLOBAL              1 (False)
              7 LOAD_GLOBAL              0 (True)
             10 BUILD_LIST               2
             13 COMPARE_OP               6 (in)
             16 RETURN_VALUE        
Roshan Mathews
fuente
13
Siempre hay un chico con él, dispero esta es una respuesta muy valiosa porque muestra que realmente not inse usa
2015
21
Bytecode es un detalle de implementación del intérprete CPython. Esta es una respuesta de CPython a una pregunta de Python, de hecho, se puede responder mejor directamente desde la referencia del lenguaje.
wim
55
@wim Yo diría que la implementación de bytecode no es tan importante como el desmontaje real. Se garantiza que otras implementaciones generarán algo funcionalmente idéntico, por lo que comprender un desensamblaje ofrece información suficiente para comprender el "por qué" y no el "cómo" de bajo nivel.
Alex Pana
36

Precedencia del operador. inse une más fuerte que not, por lo que su expresión es equivalente a not((True) in [False, True]).

mooiamaduck
fuente
33

Se trata de la precedencia del operador ( ines más fuerte que not). Pero se puede corregir fácilmente agregando paréntesis en el lugar correcto:

(not(True)) in [False, True]  # prints true

escritura:

not(True) in [False, True]

es lo mismo que:

not((True) in [False, True])

que se ve si Trueestá en la lista y devuelve el "no" del resultado.

alfasin
fuente
14

Está evaluando como not True in [False, True], que regresa Falseporque Trueestá en[False, True]

Si intentas

>>>(not(True)) in [False, True]
True

Obtienes el resultado esperado.

usuario3636636
fuente
13

Junto con las otras respuestas que mencionaron que la precedencia de notes menor que in, en realidad su declaración es equivalente a:

not (True in [False, True])

Pero tenga en cuenta que si no separa su condición de las otras, python usará 2 roles ( precedenceo chaining) para separar eso, y en este caso python utilizó la precedencia. Además, tenga en cuenta que si desea separar una condición, debe poner todas las condiciones entre paréntesis, no solo el objeto o valor:

(not True) in [False, True]

Pero como se mencionó, hay otra modificación por python en los operadores que está encadenando :

Basado en la documentación de Python :

Tenga en cuenta que las comparaciones, las pruebas de membresía y las pruebas de identidad tienen la misma prioridad y tienen una función de encadenamiento de izquierda a derecha como se describe en la sección Comparaciones.

Por ejemplo, el resultado de la siguiente declaración es False:

>>> True == False in [False, True]
False

Porque python encadenará las declaraciones de la siguiente manera:

(True == False) and (False in [False, True])

Que es exactamente False and Trueeso es False.

Puede suponer que el objeto central se compartirá entre 2 operaciones y otros objetos (falso en este caso).

Y tenga en cuenta que también es cierto para todas las comparaciones, incluidas las pruebas de membresía y las operaciones de pruebas de identidad que son los siguientes operandos:

in, not in, is, is not, <, <=, >, >=, !=, ==

Ejemplo:

>>> 1 in [1,2] == True
False

Otro ejemplo famoso es el rango de números:

7<x<20

que es igual a:

7<x and x<20   
Kasramvd
fuente
6

Veámoslo como una operación de comprobación de la contención de la colección: [False, True]es una lista que contiene algunos elementos.

La expresión True in [False, True]regresa True, como Truees un elemento contenido en la lista.

Por lo tanto, not True in [False, True]da el resultado "booleano opuesto" notde la expresión anterior (sin paréntesis para preservar la precedencia, ya que intiene mayor precedencia que el notoperador). Por lo tanto, not Trueresultará False.

Por otro lado, (not True) in [False, True]es igual a False in [False, True], que es True( Falseestá contenido en la lista).

Nick Louloudakis
fuente
6

Para aclarar algunas de las otras respuestas, agregar paréntesis después de un operador unario no cambia su precedencia. not(True)No hace que la notunión sea más fuerte True. Es solo un conjunto redundante de paréntesis True. Es casi lo mismo que (True) in [True, False]. Los paréntesis no hacen nada. Si desea que el enlace sea más ajustado, debe poner los paréntesis alrededor de toda la expresión, es decir, tanto el operador como el operando, es decir,(not True) in [True, False] .

Para ver esto de otra manera, considere

>>> -2**2
-4

**se une más fuerte que -, por lo que obtienes el negativo de dos al cuadrado, no el cuadrado de dos negativos (que sería positivo cuatro).

¿Qué pasaría si quisieras el cuadrado de dos negativos? Obviamente, agregarías paréntesis:

>>> (-2)**2
4

Sin embargo, no es razonable esperar que lo siguiente dé 4

>>> -(2)**2
-4

porque -(2)es la misma que -2. Los paréntesis no hacen absolutamente nada. not(True)Es exactamente lo mismo.

asmeurer
fuente