2013-11-15 82 views
69

我正在寫一個拒絕未經授權用戶訪問的安全系統。爲什麼`a == b或c或d`總是評估爲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.") 

它按預期授予授權用戶的訪問權限,但它也允許未經授權的用戶使用!

Hello. Please enter your name: 
Bob 
Access granted. 

爲什麼會發生這種情況?我明白表示只在name等於Kevin,Jon或Inbar時授予訪問權限。我也嘗試了相反的邏輯,if "Kevin" or "Jon" or "Inbar" == name,但結果是一樣的。

+0

寫作條件最常用的寫法是'如果名字在[「凱文」,「喬恩」,「Inbar」]:'' – djinn

回答

103

在許多情況下,Python的外觀和行爲與自然英語相似,但這是抽象失敗的一種情況。人們可以使用上下文線索來確定「Jon」和「Inbar」是連接到動詞「equals」的對象,但Python解釋器更注重字面意思。

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

在邏輯上等同於:

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

其中,對於用戶Bob,等效於:

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

or操作員選擇的第一個參數具有正truth value

if ("Jon"): 

並且由於「Jon」具有正的真值,因此將執行if塊。不管名稱如何,這就是「授予訪問權限」的原因。

所有這些推理也適用於表達if "Kevin" or "Jon" or "Inbar" == name。第一個值"Kevin"爲true,因此將執行if塊。


有兩種常見的方法來正確構造這個條件。

  1. 使用多個==運營商明確檢查對每個值:
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. 撰寫有效值的序列,並使用in操作來測試成員:
    if name in ("Kevin", "Jon", "Inbar"):

一般情況下,第二個應該是首選,因爲它更容易閱讀也更快:

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 
相關問題