본문 바로가기

Language Syntax/Python

[Python] 논리 연산에 대한 고찰

728x90

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

위 결과에 대해 대부분은 다음과 같이 설명한다.

  1. A && BAB 가 모두 true 일 경우 true 이고, 아닐 경우 false 이다.
  2. A || BAB 가 모두 false 일 경우 false 이고, 아닐 경우 true 이다.
  3. !AA 값이 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 True1, False0 으로 계산
bool int int int True1, False0 으로 계산
bool float float float True1, False0 으로 계산
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), ab 의 값이 같으면 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 == bbool 형태의 값, 즉 True 혹은 False 로 나타난다.

이때, 값을 가지는 cbool 값을 가지는 a == b 를 곱한다는 것이 어떠한 의미를 가질까?

a == b c (a == b) * c (a == b) * c or d
True c c
False 거짓 d

위 표는 a == bc 값에 따라 결정되는 (a == b) * c or d 값을 표로써 나타낸 것이다. 표를 통해 해당식의 결과값이 a == b일 때 c, 거짓일 때 d 임을 쉽게 확인할 수 있다.


관련 포스팅

728x90