「a == x or y or z」が常に True と評価されるのはなぜですか? 「a」をこれらすべてと比較するにはどうすればいいですか? 質問する

「a == x or y or z」が常に True と評価されるのはなぜですか? 「a」をこれらすべてと比較するにはどうすればいいですか? 質問する

権限のないユーザーのアクセスを拒否するセキュリティ システムを作成しています。

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

期待どおりに承認されたユーザーにアクセスを許可しますが、承認されていないユーザーもアクセスできるようになります。

Hello. Please enter your name: Bob
Access granted.

なぜこのようなことが起こるのでしょうか? が Kevin、Jon、または Inbar に等しい場合にのみアクセスを許可するように明確に指定しましたname。また、反対のロジックも試しましたif "Kevin" or "Jon" or "Inbar" == nameが、結果は同じでした。


この質問は、この非常に一般的な問題の標準的な重複ターゲットとして意図されています。別の人気のある質問があります複数の変数が単一の値と等しいかどうかをテストするにはどうすればよいでしょうか?基本的な問題は同じですが、比較対象が逆になっています。この問題は Python 初心者が遭遇するもので、逆の質問の知識を自分の問題に適用するのが難しい可能性があるため、この質問は重複として閉じるべきではありません。

inの代わりに、==次のような解があります。リスト内の複数の値のメンバーシップをテストする方法

ベストアンサー1

多くの場合、Python は自然な英語のように見え、動作しますが、これはその抽象化が失敗した 1 つの例です。コンテキストの手がかりを使用して、「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最初のオペランドを選択するあれは「真実の」つまり、if条件を満たすだろう(または、どれも「真実」でない場合は最後のもの):

if "Jon":

「Jon」は真なので、ifブロックが実行されます。これにより、指定された名前に関係なく、「Access authorized」が印刷されます。

このすべての推論は式 にも当てはまりますif "Kevin" or "Jon" or "Inbar" == name。最初の値"Kevin"は true なので、ifブロックが実行されます。


この条件文を適切に構築するには、3 つの一般的な方法があります。

  1. 複数の==演算子を使用して、各値を明示的にチェックします。

    if name == "Kevin" or name == "Jon" or name == "Inbar":
    
  2. 有効な値のコレクション (セット、リスト、タプルなど) を作成し、in演算子を使用してメンバーシップをテストします。

    if name in {"Kevin", "Jon", "Inbar"}:
    
  3. 使用any()そしてジェネレータ式ループ内の各値を明示的にチェックするには:

    if any(name == auth for auth in ["Kevin", "Jon", "Inbar"]):
    

一般的には、読みやすく、高速であるため、2 番目の方法が推奨されます。

>>> import timeit
>>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"',
    setup="name='Inbar'")
0.0960568820592016
>>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
0.034957461059093475
>>> timeit.timeit('any(name == auth for auth in ["Kevin", "Jon", "Inbar"])',
    setup="name='Inbar'")
0.6511583919636905

実際にこのように解析されるという証明を知りたい人のために、if a == b or c or d or e: ...組み込みastモジュールが答えを提供します:

>>> import ast
>>> ast.parse("a == b or c or d or e", "<string>", "eval")
<ast.Expression object at 0x7f929c898220>
>>> print(ast.dump(_, indent=4))
Expression(
    body=BoolOp(
        op=Or(),
        values=[
            Compare(
                left=Name(id='a', ctx=Load()),
                ops=[
                    Eq()],
                comparators=[
                    Name(id='b', ctx=Load())]),
            Name(id='c', ctx=Load()),
            Name(id='d', ctx=Load()),
            Name(id='e', ctx=Load())]))

ご覧のとおり、これはor4 つのサブ式 (比較a == b、 、および単純式cd、 )eに適用されたブール演算子です。

おすすめ記事