[python] 왜`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.

왜 이런 일이 발생합니까? nameKevin, Jon 또는 Inbar와 같을 때만 액세스 권한을 부여하겠다고 명시했습니다 . 나는 또한 반대 논리를 시도 if "Kevin" or "Jon" or "Inbar" == name했지만 결과는 동일합니다.



답변

대부분의 경우 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연산자 포지티브 첫번째 인수 선택 진리 값 :

if ("Jon"):

그리고 “Jon”은 양의 진리 값을 가지므로 if블록이 실행됩니다. 이것이 이름에 관계없이 “액세스 권한 부여”가 인쇄되는 원인입니다.

이 모든 추론은 표현에도 적용됩니다 if "Kevin" or "Jon" or "Inbar" == name. 첫 번째 값 "Kevin"은 참이므로 if블록이 실행됩니다.


이 조건부를 적절하게 구성하는 두 가지 일반적인 방법이 있습니다.

  1. 여러 ==연산자를 사용 하여 각 값을 명시 적으로 확인합니다.
    if name == "Kevin" or name == "Jon" or name == "Inbar":

  2. 유효한 값의 시퀀스를 작성하고 in연산자를 사용하여 멤버 자격을 테스트합니다.
    if name in {"Kevin", "Jon", "Inbar"}:

일반적으로 두 번째는 읽기 쉽고 빠르기 때문에 선호되어야합니다.

>>> 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

if a == b or c or d or e: ...실제로 이와 같이 구문 분석 되는 증명을 원하는 사람들을 위해 . 내장 ast모듈은 다음과 같은 답을 제공합니다.

>>> import ast
>>> ast.parse("if a == b or c or d or e: ...")
<_ast.Module object at 0x1031ae6a0>
>>> ast.dump(_)
"Module(body=[If(test=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())]), body=[Expr(value=Ellipsis())], orelse=[])])"
>>>

소위 testif이 같은 문 외모 :

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())
 ]
)

사람이 볼 수 있듯이, 상기 부울 연산자의 or여러 적용 values, 즉 a == bc, de.


답변

간단한 엔지니어링 문제입니다. 좀 더 자세히 살펴 보겠습니다.

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

그러나 C 언어에서 상속 된 Python은 0이 아닌 정수의 논리 값을 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')

안전을 위해 암호를 하드 코딩하지 않는 것이 좋습니다.


답변

3 개의 상태 확인이 있습니다. if name == "Kevin" or "Jon" or "Inbar":

  • 이름 == “케빈”
  • “존”
  • “인바”

이 if 문은 다음과 같습니다.

if name == "Kevin":
    print("Access granted.")
elif "Jon":
    print("Access granted.")
elif "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

때문에 elif "Jon"항상 true가됩니다 모든 사용자에 대한 액세스 권한이 부여되도록

해결책


아래 방법 중 하나를 사용할 수 있습니다.

빠른

if name in ["Kevin", "Jon", "Inbar"]:
    print("Access granted.")
else:
    print("Access denied.")

느린

if name == "Kevin" or name == "Jon" or name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")

느림 + 불필요한 코드

if name == "Kevin":
    print("Access granted.")
elif name == "Jon":
    print("Access granted.")
elif name == "Inbar":
    print("Access granted.")
else:
    print("Access denied.")


답변