프로그래밍을 처음 배우는 사람들이 흔히 저지르는 실수 중 하나는 불리언(Boolean) 연산자의 동작 방식을 잘못 이해하는 것입니다. 이는 파이썬 인터프리터가 표현식을 읽고 처리하는 방식에서 비롯됩니다. 예를 들어, 'and'와 'or' 문을 막 배운 후에는 X = ('x' or 'y')라는 표현식이 변수 X가 문자열 'x' 또는 'y'와 같은지 확인한다고 생각하기 쉽습니다. 하지만 실제로는 전혀 다르게 동작합니다.
무슨 말인지 이해하려면 인터프리터와 대화형 세션을 시작한 뒤 다음 표현식들을 직접 입력해 보세요.
>>> 'x' == ('x' or 'y')
True
>>> 'y' == ('x' or 'y')
False
>>> 'x' == ('x' and 'y')
False
>>> 'y' == ('x' and 'y')
True
이 결과를 보면 and와 or 연산자가 마치 고장 난 것처럼 느껴질 수 있습니다. 처음 두 표현식에서 'x'는 'x' or 'y'와 동일한데 'y'는 그렇지 않다는 점, 그리고 'y'가 'x' and 'y'와 동일하다는 점이 도무지 말이 되지 않아 보입니다. 하지만 인터프리터가 불리언 연산자를 어떻게 처리하는지 살펴보면, 이 결과들은 사실 요청한 대로 정확히 동작한 것입니다. 다만 여러분이 생각했던 방식과 다를 뿐입니다.
or 표현식의 동작 원리
or 표현식의 경우, 파이썬 인터프리터는 먼저 첫 번째 문장을 가져와 참인지 확인합니다. 첫 번째 문장이 참이면, 파이썬은 두 번째 인수를 살펴보지 않고 곧바로 해당 객체의 값을 반환합니다. or 표현식에서는 값 중 하나라도 참이면 전체가 참이 되기 때문에 두 번째 문장을 확인할 필요가 없기 때문입니다. 반대로 첫 번째 값이 거짓으로 평가되면, 파이썬은 두 번째 문장을 검사하고 그 값을 반환합니다. 첫 번째 절반이 거짓이었으므로 두 번째 절반이 표현식의 진리값을 결정하게 됩니다.
인터프리터의 이러한 "게으른" 동작 방식을 단락 평가(short-circuiting)라고 부르며, 많은 프로그래밍 언어에서 불리언 표현식을 평가할 때 널리 사용되는 방식입니다.
and 표현식의 동작 원리
and 표현식에서도 파이썬은 단락 기법을 활용해 진리값 평가 속도를 높입니다. 첫 번째 문장이 거짓이면 전체가 반드시 거짓이므로 해당 객체 값(거짓)을 바로 반환하고, 첫 번째 값이 참이라면 두 번째 값을 검사한 후 그 값을 반환합니다.
그럼 코드를 처리하는 과정에서 인터프리터가 무엇을 "보는지" 네 가지 경우로 나누어 단계별로 살펴보겠습니다.
첫 번째 경우
'x' == ('x' or 'y') # 괄호를 먼저 확인하므로 "('x' or 'y')"를 평가
# 'x'는 빈 문자열이 아니므로 첫 번째 값은 True
>>> 'x' == 'x' # 문자열 'x'는 문자열 'x'와 동일하므로 표현식은 True
True
두 번째 경우
'y' == ('x' or 'y') # 괄호를 먼저 확인하므로 "('x' or 'y')" 표현식을 평가
# 'x'는 빈 문자열이 아니므로 첫 번째 값은 True
# 첫 번째 값 반환: 'x'
'y' == 'x' # 문자열 'y'는 문자열 'x'와 동일하지 않으므로 표현식은 False
세 번째 경우
>>> 'x' == ('x' and 'y') # 괄호를 먼저 확인하므로 "('x' and 'y')" 표현식을 평가
# 'x'는 빈 문자열이 아니므로 첫 번째 값은 True, 두 번째 값 검사
# 'y'는 빈 문자열이 아니므로 두 번째 값은 True
# 전체 표현식의 결과로 두 번째 값 반환: 'y'
>>> 'x' == 'y' # 문자열 'x'는 문자열 'y'와 동일하지 않으므로 표현식은 False
False
네 번째 경우
>>> 'y' == ('x' and 'y') # 괄호를 먼저 확인하므로 "('x' and 'y')" 표현식을 평가
# 'x'는 빈 문자열이 아니므로 첫 번째 값은 True, 두 번째 값 검사
# 'y'는 빈 문자열이 아니므로 두 번째 값은 True
# 전체 표현식의 결과로 두 번째 값 반환: 'y'
>>> 'y' == 'y' # 문자열 'y'는 문자열 'y'와 동일하므로 표현식은 True
True
단락 평가(short-circuit evaluation)란 AND나 OR처럼 불리언 표현식을 평가할 때, 해당 표현식을 만족하거나 부정하는 첫 번째 조건을 발견하는 즉시 평가를 중단할 수 있다는 의미입니다. 이를 활용하면 불필요한 연산을 줄여 코드 실행 속도를 개선할 수 있습니다.
파이썬 공식 문서에 설명된 단락 평가 규칙은 다음과 같습니다.
| 연산 | 결과 | 설명 |
|---|---|---|
| x or y | x가 거짓이면 y, 그렇지 않으면 x | 첫 번째 인수가 거짓일 때만 두 번째 인수(y)를 평가함 |
| x and y | x가 거짓이면 x, 그렇지 않으면 y | 첫 번째 인수(x)가 참일 때만 두 번째 인수(y)를 평가함 |
| not x | x가 거짓이면 True, 그렇지 않으면 False | not은 비-불리언 연산자보다 우선순위가 낮음 |