権限のないユーザーへのアクセスを拒否するセキュリティシステムを作成しています。
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
、しかし結果は同じです。
多くの場合、Pythonは自然な英語のように見え、動作しますが、これはその抽象化が失敗する1つのケースです。人々はコンテキスト手がかりを使用して、「Jon」動詞は「等しい」が、Pythonインタープリターはより文字通り考えられる。
if name == "Kevin" or "Jon" or "Inbar":
論理的には次と同等です:
if (name == "Kevin") or ("Jon") or ("Inbar"):
ユーザーBobの場合、これは次と同等です。
if (False) or ("Jon") or ("Inbar"):
or
演算子は、正の 真理値 を持つ最初の引数を選択します。
if ("Jon"):
また、「Jon」には正の真理値があるため、if
ブロックが実行されます。これが、指定された名前に関係なく「アクセス許可」が印刷される原因です。
この推論はすべて、式if "Kevin" or "Jon" or "Inbar" == name
にも適用されます。最初の値"Kevin"
はtrueであるため、if
ブロックが実行されます。
この条件を適切に構築するには、2つの一般的な方法があります。
複数の==
演算子を使用して、各値に対して明示的にチェックします。if name == "Kevin" or name == "Jon" or name == "Inbar":
有効な値のシーケンスを作成し、in
演算子を使用してメンバーシップをテストします。if name in {"Kevin", "Jon", "Inbar"}:
一般に、2つ目は読みやすく、高速であるため、2つ目を優先する必要があります。
>>> 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
単純なエンジニアリングの問題です。もう少し簡単に説明しましょう。
In [1]: a,b,c,d=1,2,3,4
In [2]: a==b
Out[2]: False
しかし、言語Cから継承されたPythonは、ゼロ以外の整数の論理値をTrueとして評価します。
In [11]: if 3:
...: print ("yey")
...:
yey
ここで、Pythonはそのロジック上に構築され、整数などの論理リテラルを使用できるようになります。
In [9]: False or 3
Out[9]: 3
最後に
In [4]: a==b or c or d
Out[4]: 3
適切な記述方法は次のとおりです。
In [13]: if a in (b,c,d):
...: print('Access granted')
安全のために、パスワードをハードコーディングしないこともお勧めします。