¿Por qué `a ==b o c o d` siempre evalúa a Verdadero

python boolean boolean-expression


Estoy escribiendo un sistema de seguridad que niega el acceso a usuarios no autorizados.

import sys

print("Hello. Please enter your name:")
name = sys.stdin.readline().strip()
if name == "Kevin" or "Jon" or "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

Concede el acceso a los usuarios autorizados como se esperaba,pero también deja entrar a los usuarios no autorizados!

Hello. Please enter your name:
Bob
Access granted.

¿Por qué ocurre esto? He declarado claramente que solo concede acceso cuando el name es igual a Kevin, Jon o Inbar. También probé la lógica opuesta, if "Kevin" or "Jon" or "Inbar" == name , pero el resultado es el mismo.




Answer 1 Kevin


En muchos casos,Python se ve y se comporta como el inglés natural,pero este es un caso en el que esa abstracción falla.La gente puede usar pistas de contexto para determinar que "Jon" e "Inbar" son objetos unidos al verbo "equals",pero el intérprete de Python es más literal.

if name == "Kevin" or "Jon" or "Inbar":

es lógicamente equivalente a:

if (name == "Kevin") or ("Jon") or ("Inbar"):

Lo cual,para el usuario Bob,es equivalente a:

if (False) or ("Jon") or ("Inbar"):

El operador or elige el primer argumento con un valor de verdad positivo :

if ("Jon"):

Y como "Jon" tiene un valor de verdad positivo, el bloque if se ejecuta. Eso es lo que hace que se imprima "Acceso otorgado" independientemente del nombre dado.

Todo este razonamiento también se aplica a la expresión if "Kevin" or "Jon" or "Inbar" == name . el primer valor, "Kevin" , es verdadero, por lo if se ejecuta el bloque if .


Hay dos formas comunes de construir adecuadamente este condicional.

  1. Utilice múltiples operadores == para verificar explícitamente cada valor:
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. Componga una secuencia de valores válidos y use el operador in para probar la membresía:
    if name in {"Kevin", "Jon", "Inbar"}:

En general,de los dos,se debería preferir el segundo,ya que es más fácil de leer y también más rápido:

>>> import timeit
>>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"', setup="name='Inbar'")
0.4247764749999945
>>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
0.18493307199999265



Answer 2 user1854182


Un simple problema de ingeniería,vamos un poco más allá.

In [1]: a,b,c,d=1,2,3,4
In [2]: a==b
Out[2]: False

Pero,heredado del lenguaje C,Python evalúa el valor lógico de un entero no cero como Verdadero.

In [11]: if 3:
    ...:     print ("yey")
    ...:
yey

Ahora,Python se basa en esa lógica y te permite usar literales lógicos como o en números enteros,y así

In [9]: False or 3
Out[9]: 3

Finally

In [4]: a==b or c or d
Out[4]: 3

La manera apropiada de escribirlo sería:

In [13]: if a in (b,c,d):
    ...:     print('Access granted')

Por seguridad,también le sugiero que no codifique las contraseñas.