2013-11-15 11 views
69

Sto scrivendo un sistema di sicurezza che nega l'accesso agli utenti non autorizzati.Perché `a == b o c o d` valuti sempre su True?

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.") 

Fornisce l'accesso agli utenti autorizzati come previsto, ma consente anche agli utenti non autorizzati!

Hello. Please enter your name: 
Bob 
Access granted. 

Perché si verifica? Ho chiaramente dichiarato di concedere l'accesso solo quando name è uguale a Kevin, Jon o Inbar. Ho anche provato la logica opposta, if "Kevin" or "Jon" or "Inbar" == name, ma il risultato è lo stesso.

+0

Modo più idiomatica di scrivere la condizione sarà 'se il nome in [ "Kevin", "Jon", "Inbar"]:' – djinn

risposta

103

In molti casi, Python ha l'aspetto e si comporta come un inglese naturale, ma questo è un caso in cui tale astrazione fallisce. Le persone possono usare indizi di contesto per determinare che "Jon" e "Inbar" sono oggetti uniti al verbo "uguale", ma l'interprete Python è più letterale.

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

è logicamente equivalente a:

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

Il che, per l'utente Bob, è equivalente a:

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

L'operatore or sceglie il primo argomento con una positiva truth value:

if ("Jon"): 

E poiché "Jon" ha un valore di verità positivo, viene eseguito il blocco if. Questo è ciò che causa la "concessione dell'accesso" a prescindere dal nome dato.

Tutti questi ragionamenti si applicano anche all'espressione if "Kevin" or "Jon" or "Inbar" == name. il primo valore, "Kevin", è true, quindi viene eseguito il blocco if.


Ci sono due modi comuni per costruire correttamente questa condizione.

  1. Usa multipla == operatori di controllare in modo esplicito contro ogni valore:
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. comporre una sequenza di valori validi, e utilizzare l'operatore in per verificare l'adesione:
    if name in ("Kevin", "Jon", "Inbar"):

In generale dei due il secondo dovrebbe essere preferito in quanto è più facile da leggere e anche più veloce:

In [1]: name = "Inbar" 

In [2]: %timeit name == "Keven" or name == "Jon" or name == "Inbar" 
10000000 loops, best of 3: 116 ns per loop 

In [3]: %timeit name in ("Keven", "Jon", "Inbar") 
10000000 loops, best of 3: 65.2 ns per loop 
Problemi correlati