[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.
왜 이런 일이 발생합니까? name
Kevin, 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
블록이 실행됩니다.
이 조건부를 적절하게 구성하는 두 가지 일반적인 방법이 있습니다.
-
여러
==
연산자를 사용 하여 각 값을 명시 적으로 확인합니다.
if name == "Kevin" or name == "Jon" or name == "Inbar":
-
유효한 값의 시퀀스를 작성하고
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=[])])"
>>>
소위 test
의 if
이 같은 문 외모 :
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 == b
과 c
, d
와 e
.
답변
간단한 엔지니어링 문제입니다. 좀 더 자세히 살펴 보겠습니다.
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.")