1. 개요
대부분의 언어는 같은 형식의 데이터끼리만 논리 연산을 할 수 있다. 하지만 Python 은 형식이 달라도 논리 연산이 가능하다는 특징이 있다. 이 포스팅에서는 Python 의 논리 연산자 (Logical Operator) and
, or
, not
이 어떻게 동작하는지에 대해 자세히 살펴보고자 한다.
2. 비 Python 의 논리 연산
대부분의 언어는 논리 연산자로 &&
, ||
, !
를 사용한다.
&&
: 논리곱 (and)||
: 논리합 (or)!
: 부정 (not)
위 세 연산자(Operator)와 편의상 A
(왼쪽) 와 B
(오른쪽) 의 피연산자(Operand)를 사용한 다음과 같은 식의 연산값에 대해 살펴보도록 하자.
A && B
A || B
!A
기본적으로 위 연산의 결과값은 bool
형식을 나타내며, 다음의 진리표를 만족한다. 단, C 언어와 같이 bool
형식이 존재하지 않는 경우, int
형식으로 대체되기도 한다.
A && B
A |
B |
A && B |
---|---|---|
true |
true |
true |
true |
false |
false |
false |
true |
false |
false |
false |
false |
A || B
A |
B |
A || B |
---|---|---|
true |
true |
true |
true |
false |
true |
false |
true |
true |
false |
false |
false |
!A
A |
!A |
---|---|
true |
false |
false |
true |
위 결과에 대해 대부분은 다음과 같이 설명한다.
A && B
는A
와B
가 모두true
일 경우true
이고, 아닐 경우false
이다.A || B
는A
와B
가 모두false
일 경우false
이고, 아닐 경우true
이다.!A
는A
값이true
일 때false
,A
값이false
일 때true
이다.
하지만 프로그래밍 언어에서는 연산의 효율을 추구하기 때문에 일부 판단을 생락하기도 한다.
가령 A && B
의 식을 연산한다고 할 때, A
값이 false
일 경우, B
값은 확인해볼 필요도 없이 연산 결과는 false
가 된다. 반대로, A || B
에서 A
값이 true
일 경우, B
값과 관계 없이 true
가 된다.
A && B
A == true
이면A && B
의 값은B
값에 따라 달라짐A == false
이면A && B == false
A || B
A == true
이면A || B == true
A == false
이면A || B
의 값은B
값에 따라 달라짐
위와 같은 방법을 채택하여 프로그램의 연산 효율을 증가시킨다.
3. Python 의 논리 연산
Python 에서는 일반적인 언어와 달리 and
, or
, not
의 논리 연산자를 사용한다.
A and B
A or B
not A
Python 이 다른 언어와 다른 특징은 논리 연산에 대해 bool
형식 또는 int
형식으로만 한정되지 않는다는 점이다. 형식에 따라 어떠한 값이 참 또는 거짓으로 인식되는지 먼저 알아볼 필요가 있다.
형식 | 참 | 거짓 |
---|---|---|
bool |
True |
False |
int |
0 을 제외한 모든 값 |
0 |
float |
.0 을 제외한 모든 값 |
.0 |
str |
'' 을 제외한 모든 값 |
'' |
list |
[] 을 제외한 모든 값 |
[] |
다음으로 이 언어가 논리 연산을 수행하는 방법에 대해 살펴보자.
3.1. and
연산자
Python 에서의 and
연산은 다음과 같이 이루어진다.
A
가 참이면A and B == B
A
가 거짓이면A and B == A
사실 바로 이해가 되지 않는 개념일 수 있지만, 위에서 설명한 비 Python 언어의 논리 연산 처리방식과 유사하다.
다음 예시를 살펴보자.
print(True and 1) # 1
print(True and 0) # 0
print(False and 1) # False
print(False and 0) # False
출력결과
1
0
False
False
위 예시에서는 bool
값과 int
값의 논리연산을 수행한다.
True and 1
:A
값이 참이므로 결과값은B
값의1
True and 0
:A
값이 참이므로 결과값은B
값의0
False and 1
:A
값이 거짓이므로 결과값은A
값의False
False and 0
:A
값이 거짓이므로 결과값은A
값의False
A
값이 거짓이면 더 볼 것도 없이 A
이고, A
값이 참일 경우 B
값의 참/거짓 여부를 판단한 후 결과값을 결정하는 연산 조차 생략하고, 결과값이 그냥 B
값 그 자체로써 결정된다.
3.2. or
연산자
or
연산은 and
와 정확히 반대로 이루어진다.
A
가 참이면A or B == A
A
가 거짓이면A or B == B
예시를 살펴보자.
print(True or 1) # True
print(True or 0) # True
print(False or 1) # 1
print(False or 0) # 0
출력결과
True
True
1
0
True or 1
:A
값이 참이므로 결과값은A
값의True
True or 0
:A
값이 참이므로 결과값은A
값의True
False or 1
:A
값이 거짓이므로 결과값은B
값의1
False or 0
:A
값이 거짓이므로 결과값은B
값의0
A
값이 참이면 더 볼 것도 없이 A
이고, A
값이 거짓일 경우 역시 B
값의 참/거짓 여부를 판단한 후 결과값을 결정하는 연산 조차 생략하고, 결과값이 그냥 B
값 그 자체로써 결정된다.
3.3. not
연산자
not
연산자는 and
, or
과 달리 반드시 bool
값의 결과만 도출한다.
위에서 언급한 형식에 따른 참/거짓 인식값을 나타낸 표와 관련하는데, A
값이 참으로 인식되면 not
연산 결과값은 False
, 거짓으로 인식되면 결과값은 True
를 나타낸다.
A
가 참이면not A == False
A
가 거짓이면not A == True
예시를 살펴보자.
print(not 0) # True
print(not 3) # False
print(not .0) # True
print(not -.5) # False
print(not '') # True
print(not 'hello') # False
print(not []) # True
print(not [1, '3']) # False
출력결과
True
False
True
False
True
False
True
False
4. 곱셈과 덧셈
그렇다면 Python 의 곱셈(*
) 및 덧셈(+
) 은 논리곱(and
) 및 논리합(or
) 과 어떤 차이가 있을까?
Python 의 곱셈과 덧셈은 상당히 직관적이고 확장적으로 구현되어 있다.
피연산자가 각각 어떠한 형식을 가지는지에 따라 연산방식이 달라진다. 피연산자에 따라 어떠한 연산 결과값의 형식이 도출되는지에 관해 표로 정리하면 다음과 같다.
A |
B |
A * B |
A + B |
비고 |
---|---|---|---|---|
bool |
bool |
int |
int |
True 는 1 , False 는 0 으로 계산 |
bool |
int |
int |
int |
True 는 1 , False 는 0 으로 계산 |
bool |
float |
float |
float |
True 는 1 , False 는 0 으로 계산 |
bool |
list |
list |
TypeError |
곱만 가능 |
int |
int |
int |
int |
|
int |
float |
float |
float |
|
int |
list |
list |
TypeError |
곱만 가능 |
float |
float |
float |
float |
|
float |
list |
TypeError |
TypeError |
런타임 오류 발생 |
list |
list |
TypeError |
list |
합만 가능 |
주목할 점은 bool
형식과 int
, float
, list
형식의 곱이 모두 가능하다는 점이다.
이때, bool
형식이 True
값을 가지면 1
로써, False
값을 가지면 0
으로써 계산된다는 특징이 있다.
따라서 True
값에 bool
형식이 아닌 임의의 값 X
을 곱한다는 것은 X
값 그 자체를, False
값에 X
를 곱한다는 것은 X
형식의 거짓 값을 의미하게 된다.
### True * X ###
print(True * True) # 1
print(True * False) # 0
print(True * 3) # 3
print(True * 0) # 0
print(True * 2.5) # 2.5
print(True * .0) # 0.0
print(True * [1, 2, 3]) # [1, 2, 3]
print(True * []) # []
print()
### False * X ###
print(False * True) # 0
print(False * False) # 0
print(False * 3) # 0
print(False * 0) # 0
print(False * 2.5) # 0.0
print(False * .0) # 0.0
print(False * [1, 2, 3]) # []
print(False * []) # []
출력결과
1
0
3
0
2.5
0.0
[1, 2, 3]
[]
0
0
0
0
0.0
0.0
[]
[]
5. 활용 예시
사실 해당 내용을 활용한다는 것은 코드의 가독성만 저해할 뿐 그렇게 바람직한 코딩 습관은 아닐 것이다. 다만 그나마 숏코딩에 요긴하게 쓰일 수 있다.
예를 들어, 변수 a
, b
, c
, d
에 대하여 (단, c
는 참), a
와 b
의 값이 같으면 c
, 다르면 d
를 출력해야 한다고 가정해보자.
보통의 구현은 다음과 같다.
if a == b: print(c)
else: print(d)
위 코드는 삼항연산자를 사용하여 더 간단히 나타낼 수 있다.
print(c if a == b else d)
논리 연산을 활용하여 이를 더 줄일 수 있다.
print((a == b) * c or d)
물론 공백까지 최대한 줄이면 최종적으로 다음과 같은 숏코딩이 완성된다.
print(c*(a==b)or d)
5.1. 설명
a == b
은 bool
형태의 값, 즉 True
혹은 False
로 나타난다.
이때, 참 값을 가지는 c
와 bool
값을 가지는 a == b
를 곱한다는 것이 어떠한 의미를 가질까?
a == b |
c |
(a == b) * c |
(a == b) * c or d |
---|---|---|---|
True |
참 | c |
c |
False |
참 | 거짓 | d |
위 표는 a == b
와 c
값에 따라 결정되는 (a == b) * c or d
값을 표로써 나타낸 것이다. 표를 통해 해당식의 결과값이 a == b
가 참일 때 c
, 거짓일 때 d
임을 쉽게 확인할 수 있다.