python - ¿Por qué "no(verdadero) en[falso, verdadero]" devuelve falso?
python-2.7 python-3.x (9)
Si hago esto:
>>> False in [False, True]
True
Eso devuelve
True
.
Simplemente porque
False
está en la lista.
Pero si lo hago:
>>> not(True) in [False, True]
False
Eso devuelve
False
.
Mientras que
not(True)
es igual a
False
:
>>> not(True)
False
¿Por qué?
Está evaluando como
not True in [False, True]
, que devuelve
False
porque
True
está en
[False, True]
Si intentas
>>>(not(True)) in [False, True]
True
Obtienes el resultado esperado.
Junto con las otras respuestas que mencionaron que la precedencia de
not
es menor que
in
,
in
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 (
precedence
o
chaining
) para separar eso, y en este caso python usó 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 el 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 3.x 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 True
que 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
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
not
una más estrechamente a
True
.
Es solo un conjunto redundante de paréntesis alrededor de
True
.
Es muy parecido a
(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
**
une más fuertemente 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 lo mismo que
-2
.
Los paréntesis no hacen absolutamente nada.
not(True)
es exactamente lo mismo.
Precedencia del operador.
in
une más fuertemente que
not
, por lo que su expresión es equivalente a
not((True) in [False, True])
.
Se trata de la
precedencia del operador
(
in
es 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
True
está en la lista y devuelve el "no" del resultado.
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]
devuelve
True
, ya que
True
es un elemento contenido en la lista.
Por lo tanto,
not True in [False, True]
da el "opuesto booleano",
not
resultado de la expresión anterior (sin paréntesis para preservar la precedencia, ya que tiene mayor precedencia que el operador).
Por lo tanto,
not True
resultará
False
.
Por otro lado,
(not True) in [False, True]
, es igual a
False in [False, True]
, que es
True
(
False
está contenido en la lista).
3.x está la documentación sobre la precedencia del operador
in binds tighter than not
Hacerlo servirá así
>>> (not True) in [False, True] True
Precedencia del operador
2.x
,
3.x
La precedencia de
not
es 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 no escribir nunca
not(True)
, preferir
not True
.
El primero hace que parezca una llamada de función, mientras que
not
es un operador, no una función.
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, se evalúa como
True not in [False, True]
, que es
False
claramente:
>>> 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
>>>
Lo que quería expresar en su lugar era
(not(True)) in [False, True]
, que como se esperaba es
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