프로그래머가 아닌 이들을 위한 파이썬 3 자습서/논리 표현식

위키책, 위키책

여기 논리 표현식(boolean expressions)[1]의 몇 가지 예제가 있다 (굳이 입력할 필요는 없다):

a = 6
b = 7
c = 42
print(1, a == 6)
print(2, a == 7)
print(3, a == 6 and b == 7)
print(4, a == 7 and b == 7)
print(5, not a == 7 and b == 7)
print(6, a == 7 or b == 7)
print(7, a == 7 or b == 6)
print(8, not (a == 7 and b == 6))
print(9, not a == 7 and b == 6)

출력되는 것:

1 True
2 False
3 True
4 False
5 True
6 True
7 False
8 True
9 False

뭐가 어떻게 된건가? 이 프로그램은 웃기는 모양새의 print 구문들 꾸러미로 구성되어 있다. 매 print 구문은 숫자와 표현식을 출력한다. 숫자는 내가 처리하고자 한 구문을 추적하는데 도움을 주기 위한 것이다. 매 표현식이 False(거짓) 또는 True(참)으로만 끝난다는 것을 유의하라. 파이썬에서는 False는 0, True는 1로도 쓰여진다.

다음 줄:

print(1, a == 6)
print(2, a == 7)

은 첫 번째 줄이 참이고, 두 번째 줄이 거짓이기 때문에 예상대로 각기 TrueFalse를 출력한다. 세 번째 출력 - print(3, a == 6 and b == 7) - 은 조금 다르다. 연산자 and는 앞의 구문과 뒤의 구문이 참이어야만 전체 표현식이 True(참)이 되고 그렇지 않으면 전체 표현식은 False(거짓)이 된다. 그 다음 줄 - print(4, a == 7 and b == 7) - 은 and 표현식의 일부가 거짓이면, 전체가 거짓이 됨을 보여준다. and의 동작은 아래와 같이 요약할 수 있다:

표현식 결과
true and true true
true and false false
false and true false
false and false false

만약 첫 번째 표현식이 거짓이면 파이썬은 전체 표현식이 거짓임을 알기 때문에 두 번째 표현식을 확인하지 않는다. False and print("Hi")True and print("Hi")를 실행시켜 그 결과를 비교해보라. 이것을 기술적으로 short-circuit evaluation라고 한다.

다음줄은 - print(5, not a == 7 and b == 7) - not연산자를 사용한다. not은 오직 표현식의 정반대의 값을 준다. (표현식은 print(5, a != 7 and b == 7)으로 재작성할 수 있다). 다음은 요약한 표이다:

표현식 결과
not true false
not false true

다음의 두 줄은 - print(6, a == 7 or b == 7)print(7, a == 7 or b == 6) - or 연산자를 사용한다. or 연산자는 첫번째 표현식이 참이거나, 두번째 표현식이 참이거나 둘다 참일 경우에만 참(True)을 반환한다. 둘다 참이 아니면 거짓(false)을 반환한다. 다음은 요약한 표이다:

표현식 결과
true or true true
true or false true
false or true true
false or false false

첫번째 표현식이 참이면 전체 표현식이 참이 되는 것을 알기 때문에, 파이썬은 두번째 표현식을 확인하지 않는다. or은 적어도 표현식의 반이 참이기만 하면 참이기 때문에 그렇다. 앞부분이 참이면 뒷부분은 참이거나 거짓일 것이지만, 전체 표현식은 여전히 참이다.

다음의 두 줄은 - print(8, not (a == 7 and b == 6))print(9, not a == 7 and b == 6) - 괄호들이 그룹 표현식으로 사용될 수 있고 한 부분이 가장 먼저 계산되도록 강제하도록 사용될 수 있다는 것을 보여준다. 괄호가 표현식이 거짓에서 참이 되도록 바꾼 것에 유의하라. This occurred since 그 괄호들은 not 이 전체 표현식에 적용되도록 강제하였다.(a == 7 부분 대신 말이다.)

다음은 논리 표현식을 사용한 예제이다:

list = ["Life", "The Universe", "Everything", "Jack", "Jill", "Life", "Jill"]

# 리스트의 복사본을 만든다. 더 많은 것을 보려면 [:] 의 의미를 설명한 리스트 장을 보라.
copy = list[:]
# 복사본을 정렬한다
copy.sort()
prev = copy[0]
del copy[0]

count = 0

# 리스트에서 일치하는 것을 찾을 때까지 작동한다
while count < len(copy) and copy[count] != prev:
    prev = copy[count]
    count = count + 1

# 일치하는 것을 찾지 못하면 count는 len보다 작을 수 없다
# 왜냐하면 while 루프는 count 가 len보다 작고 일치하는 것을 찾기 전까지
# 계속하기 때문이다

if count < len(copy):
    print("First Match:", prev)

그리고 이것은 그 결과이다:

First Match: Jill

This program works by continuing to check for match while count < len(copy) and copy[count] is not equal to prev. When either count is greater than the last index of copy or a match has been found the and is no longer true so the loop exits. The if simply checks to make sure that the while exited because a match was found.

The other "trick" of and is used in this example. If you look at the table for and notice that the third entry is "false and false". If count >= len(copy) (in other words count < len(copy) is false) then copy[count] is never looked at. This is because Python knows that if the first is false then they can't both be true. This is known as a short circuit and is useful if the second half of the and will cause an error if something is wrong. I used the first expression (count < len(copy)) to check and see if count was a valid index for copy. (If you don't believe me remove the matches "Jill" and "Life", check that it still works and then reverse the order of count < len(copy) and copy[count] != prev to copy[count] != prev and count < len(copy).)

논리 표현식 can be used when you need to check two or more different things at once.

참고: 논리 연산자[+/-]

새로 프로그래밍을 하는 사람들의 흔한 실수는 논리 연산자(Boolean Operators)가 작동하는 원리를 잘못 이해하는 데에서 온다. 논리 연산자는 파이썬 인터프리터가 논리 표현식을 읽는 방법에서 유래하기 때문이다. 예를 들어, 처음에 "and " 와 "or" 구문에 대하여 학습한 후, 누군가 표현식 x == ('a' or 'b')은 변수 x 가 문자열 'a' 이거나 'b'과 동등한지 아닌지 확인하는 것이라 추측한다. 하지만 그렇지 않다. 이것이 어떤 것을 말하고자 하는지 확인하려면, 인터프리터의 인터렉티브 세션을 시작하여 아래의 표현식을 입력한다:

>>> 'a' == ('a' or 'b')
>>> 'b' == ('a' or 'b')
>>> 'a' == ('a' and 'b')
>>> 'b' == ('a' and 'b')

그리고 이것은 이해할 수 없는 결과일 것이다:

>>> 'a' == ('a' or 'b')
True
>>> 'b' == ('a' or 'b')
False
>>> 'a' == ('a' and 'b')
False 
>>> 'b' == ('a' and 'b')
True

이 부분에서, andor 연산자가 깨진 것처럼 보인다. 이것은 이해할 수 없을 것이다. 처음의 두 표현식에서, 'a'는 ('b'가 동등하지 않은 반면) 'a' or 'b'와 동등하다는 것이다. 더 이해가 안되는 것은, 'b'는 'a' and 'b'와 동등하다는 것이다. 인터프리터가 논리 연산자와 어떤 동작을 하는지 조사한 후에는, 이러한 결과는 사실 우리가 인터프리터에 입력하였던 것을 정확하게 수행한 것이고, 우리가 묻고자 한 것과는 같지 않다는 것을 알게 된다.

When the Python interpreter looks at an or expression, it takes the first statement and checks to see if it is true. If the first statement is true, then Python returns that object's value without checking the second statement. This is because for an or expression, the whole thing is true if one of the values is true; the program does not need to bother with the second statement. On the other hand, if the first value is evaluated as false Python checks the second half and returns that value. That second half determines the truth value of the whole expression since the first half was false. This "laziness" on the part of the interpreter is called "short circuiting" and is a common way of evaluating 논리 표현식 in many programming languages.

Similarly, for an and expression, Python uses a short circuit technique to speed truth value evaluation. If the first statement is false then the whole thing must be false, so it returns that value. Otherwise if the first value is true it checks the second and returns that value.

One thing to note at this point is that the boolean expression returns a value indicating True or False, but that Python considers a number of different things to have a truth value assigned to them. To check the truth value of any given object x, you can use the fuction bool(x) to see its truth value. Below is a table with examples of the truth values of various objects:

True False
True False
1 0
0이 아닌 숫자 문자열 'None'
비어있지 않은 문자열 빈 문자열
비어있지 않은 리스트 빈 리스트
비어있지 않은 사전 빈 사전

Now it is possible to understand the perplexing results we were getting when we tested those 논리 표현식 before. Let's take a look at what the interpreter "sees" as it goes through that code:

첫 번째 케이스:

>>> 'a' == ('a' or 'b')  # 괄호를 먼저 본다, 그래서 표현식 "('a' or 'b')" 를 계산한다
                           # 'a'는 비어있지 않은 문자열이므로, 첫 번째 값은 참(True)이다
                           # 첫 번째 값을 반환한다: 'a'
>>> 'a' == 'a'           # 문자열 'a' 는 'a'와 동등하므로, 표현식은 참(True)이다
True

두 번째 케이스:

>>> 'b' == ('a' or 'b')  # 괄호를 먼저 본다, 그래서 표현식 "('a' or 'b')" 를 계산한다
                           # 'a'는 비어있지 않은 문자열이므로, 첫 번째 값은 참(True)이다
                           # 첫 번째 값을 반환한다: 'a'
>>> 'b' == 'a'           # 문자열 'b' 는 'a'와 동등하지 않으므로, 표현식은 거짓(False)이다
False 

세 번째 케이스:

>>> 'a' == ('a' and 'b') # 괄호를 먼저 본다, 그래서 표현식 "('a' and 'b')" 를 계산한다
                           # 'a'는 비어있지 않은 문자열이므로, 첫 번째 값은 참(True)이다, 두 번째 값을 조사한다
                           # 'b'는 비어있지 않은 문자열이므로, 두 번째 값은 참(True)이다
                           # 전체 표현식의 결과로써 두 번째 값을 반환한다: 'b'
>>> 'a' == 'b'           # 문자열 'a' 는 'b'와 동등하지 않으므로, 표현식은 거짓(False)이다
False

네 번째 케이스:

>>> 'b' == ('a' and 'b') # 괄호를 먼저 본다, 그래서 표현식 "('a' and 'b')" 를 계산한다
                           # 'a'는 비어있지 않은 문자열이므로, 첫 번째 값은 참(True)이다, 두 번째 값을 조사한다
                           # 'b'는 비어있지 않은 문자열이므로, 두 번째 값은 참(True)이다
                           # 전체 표현식의 결과로써 두 번째 값을 반환한다: 'b'
>>> 'b' == 'b'           # 문자열 'b' 는 'b'와 동등하므로, 표현식은 참(True)이다
True 

So Python was really doing its job when it gave those apparently bogus results. As mentioned previously, the important thing is to recognize what value your boolean expression will return when it is evaluated, because it isn't always obvious.

Going back to those initial expressions, this is how you would write them out so they behaved in a way that you want:

>>> 'a' == 'a' or 'a' == 'b' 
True
>>> 'b' == 'a' or 'b' == 'b' 
True
>>> 'a' == 'a' and 'a' == 'b' 
False
>>> 'b' == 'a' and 'b' == 'b' 
False

When these comparisons are evaluated they return truth values in terms of True or False, not strings, so we get the proper results.

예제[+/-]

password1.py

## This program asks a user for a name and a password.
# It then checks them to make sure that the user is allowed in.

name = input("What is your name? ")
password = input("What is the password? ")
if name == "Josh" and password == "Friday":
    print("Welcome Josh")
elif name == "Fred" and password == "Rock":
    print("Welcome Fred")
else:
    print("I don't know you.")

Sample runs

What is your name? Josh
What is the password? Friday
Welcome Josh
What is your name? Bill
What is the password? Money
I don't know you.

실습[+/-]

사용자가 당신의 이름을 추측하되, 프로그램이 종료될 때까지 세 번의 기회만 주는 프로그램을 작성하라.

틀:Solution

역주[+/-]

  1. 일반적으로 어학사전이나 IT용어사전에서는 불 연산식으로 번역하고 있으며, 일반적으로 불린 대수식, 불린 표현식, 불 표현식, 부울 연산법, 불리언 표현식 등의 용어로도 사용되고 있다. 여기서는 기존의 2.x판에서의 번역은 부울 표현식을 사용하는 점, 정규 표현식(regular expressions)이라는 용어가 있는 점, 불린형의 다른 표현이 논리형인 점, 무엇보다 부울(불)이라는 학자의 이름보다 논리라는 용어가 누구에게나 쉽게 이해되는 점을 고려하여 논리 표현식으로 번역하였다.
For 루프 사전

스크립트 오류: "TScope" 모듈이 없습니다.