🚦Summary
- “&” 과 “and”는 모두 표현식 이며, 비교연산에 사용될 수 는 있지만, 그 용도와 작동 방식이 다릅니다.
- 같은 ‘and’라는 단어적 의미로 이해를 하고 구분 없이 사용하면 올바른 코드를 작성했음에도 불구하고 잘못된 결과를 도출하는 문제가 발생할 수 있습니다.
- 그 원인은 바로 연산우선순위와, 비트연산이라는 차이에서 기인하며, 이로 인해 예상과는 다른 연산을 하게 됩니다.
- 따라서 각각의 특성을 고려해 목적에 맞게 사용하는 것이 중요합니다.
- 다만, 조건문(Conditional Statement) 에서는 반드시 ‘and’ 연산자를 사용해야 예상치 못한 연산오류 없이 원하는 결과를 얻을 수 있습니다.
📌 Intro.
- 저는 현재 부트캠프에 참여하여 AI에 대해 배우는 중입니다. 최근 python의 기초개념에 대해 배우고 있는데, 여러 문제를 푸는 과정에서 ‘and’ 연산자로 조건식을 썼을 때와 ‘&’ 연산자로 조건식을 썼을 때, 기대와는 다르게 결과에 차이가 있었는데, 그 원인을 질문하는 동기 그루분의 질문이 있었습니다. (이 문제에 대한 내용은 거북이 미로찾기 문제에서 나온 것이었습니다. 👉 ‘거북이 미로찾기’ 클릭 시 해당 문제 풀이로 이어집니다.)
- 저도 당연히 둘 다 말그대로 ‘and’ 조건으로 쓰는 표현식이라 생각을 했고, 둘의 차이가 뭐길래 결과값이 달라지는 경우가 생기는지 궁금했습니다.
- 질문에 대한 답은 어느정도 들었지만, 사실 잘 이해가 가지 않았습니다. 그래서 하나 하나 찾아보고 정리를 해보려고 합니다.
Python에서 ‘and’와 ‘&’ 의 차이점 이해하기
-
Python 프로그래밍 언어에서 ‘and’와 ‘&’는 모두 표현식에 사용되지만, 두 연산자 사이에는 근본적인 차이가 있습니다. ‘and’는 두 표현식이 논리적으로 참인지 테스트하는 ‘논리 연산자’ 입니다. 반면 ‘&’ 연산자는 ‘비트 단위 연산자’ 로, 비트에 대해 작동하며 비트 단위의 연산을 수행합니다.
-
Python에서는 비어있는 내장 객체들이 논리적으로 False로 처리됩니다. 반면에 비어있지 않은 내장 객체들은 논리적으로 True로 간주됩니다.
- 좀 더 풀어서 말하자면 빈 리스트(‘[ ]’), 빈 딕셔너리( ‘{ }’ ), 빈 세트 ( ‘set()’ ) 등은 모두 False라 판단합니다.
- 반면에 이 리스트, 딕셔너리, 세트에 어떠한 유형이든 ( ‘’ 로 표현되는 빈문자열이 있다고 해도) 값이 채워져 있다면, True라 판단합니다.
- 이에 대한 다양한 예제를 코드로 보자면 아래와 같습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 빈 리스트, 튜플, 딕셔너리, 세트
print(bool([])) # False
print(bool(())) # False
print(bool({})) # False
print(bool(set())) # False
# 비어 있지 않은 리스트, 튜플, 딕셔너리, 세트
print(bool([1])) # True
print(bool((1,))) # True
print(bool({'key': 'value'})) # True
print(bool(set([1]))) # True
# 빈 문자열과 비어 있지 않은 문자열
print(bool('')) # False
print(bool('text')) # True
# 숫자 0과 0이 아닌 숫자
print(bool(0)) # False
print(bool(1)) # True
print(bool(-1)) # True
print(bool(0.1)) # True
-
이처럼 객체에 대해 python이 True인지 False인지 판단 하는 기준이 있는 것은 사용자로 하여금 다양한 연산과 비교의 작업을 더 수월하게 할 수 있도록 합니다.
-
예를들어 이러한 특성을 사용해 단순히 값이 True이다 False이다를 판단하는 것 뿐만 아니라 이를 응용해 조건문에 쓰일 수도 있고, 특정 코드의 실행을 위한 Trigger 가 될 수 도 있습니다.
-
일반적으로 알려져 있는 ‘and’와 ‘&’의 차이점을 표로 정리하면 아래와 같습니다.
- 정수값이 0일 경우 파이썬에서는 False로 간주합니다. 하지만 논리적으로 사용될때는 True로 간주됩니다. 이것은 ‘and’가 두 표현식이 논리적으로 참인지 거짓인지를 테스트 하는 반면, ‘&’는 두 문장의 결과에 대한 비트별 and 연산을 수행하기 때문입니다.
파라미터 | ‘and’연산자 in python | ‘&’연산자 in python |
---|---|---|
기본 | 두 피연산자가 모두 참일때 참을 반환 | 비트 단위 연산을 수행 |
True 표현식 | 두 표현식이 논리적(logically)으로 ‘True’ 로 쓰였는지를 판단 | T/F value들과 함께 쓰일 때, 두개의 value가 모두 True인지 테스트 |
-
아직은 좀 어려운 것 같습니다. 결국 “둘 다 ‘비교’ 할때 쓰는거고 둘다 ‘True’인지 ‘False’인지 판단할 때 쓸 수 있다는 것 같은데, 그냥 판단을 할 때 사용하는 값과, 방법이 다르다는거 아닌가?!” 라는 생각이 들 뿐입니다.
-
좀 더 각각의 개념을 뜯어볼 필요가 있어 보입니다. 파이썬에서 말하는 ‘논리적(Logical)’이란 것의 정의는 무엇이며, 비트연산이란건 또 무엇인지 이것들을 알아야 이해가 될 것 같습니다.
-
일단은 python에서 정의하는 ‘and’와 ‘&’ 가 무엇인지부터 좀 더 상세히 알아보면 좋을 것 같습니다.
Python에서 “and” 란 무엇인가?!
- ‘and’ 는 두 피연산자(and 앞뒤에 있는 값이나 표현식, 조건 등)가 모두 True일때 True를 반환(데이터 타입이 bool)하는 논리적 And 연산자로서 논리연산자(Comparison Operators)의 하나 입니다.
- 여기서 말하는 ‘논리적인(Logically)’ 란 말은 Boolean 값이나 조건문에서 주로 사용되는 개념인데, 어떤 값이 True인지 False인지를 나타냅니다.
- ‘python에서 모든 값은 기본적으로 True 또는 False 이다.’ 라는 전제가 있기 때문에 이 개념의 적용이 가능합니다. 이를 파이썬에서는 trueiness(논리적 진리성)이라 하며, 위에서 살펴본 비어있는 리스트, 딕셔너리, 세트와 값이 있는 것들간의 비교가 성립하는 이유이기도 합니다.
Python에서 “&” 란 무엇인가?!
- ‘&’는 Python에서 사용되는 비트 연산자로, 정수의 이진수 표현에서 각 비트별로 ‘and’ 연산을 수행하여 그 결과를 return합니다.
- 즉, 두 정수의 이진수에 대해서 해당 비트의 값이 모두 ‘1’일때만 그 비트를 ‘1’ 이라고 return합니다.
- 예를들어, 두 정수 5(이진수로는 ‘101’)와 3(이진수로는 ‘011’)에 대해 ‘&’ 연산을 하면, 각 비트를 비교하여 return합니다.
- 즉,
101 & 011
로 비교를 하며, 그 결과는001
이 되어 ‘1’ 이라는 비트값을 return합니다. - 만약 결과값이 ‘0’ 이면 ‘0’ 이라는 비트값을 return합니다.
- 즉,
- 예를들어, 두 정수 5(이진수로는 ‘101’)와 3(이진수로는 ‘011’)에 대해 ‘&’ 연산을 하면, 각 비트를 비교하여 return합니다.
- 예를 들어, 두 정수의 비트를 각각 비교해서 두 비트의 값이 모두 ‘1’ 이면 해당 비트의 값은 ‘1’ 이라 return합니다. 이때 파이썬에서 개념적으로 1은 True이기때문에 이 경우를 True로 판단합니다.
- 반대로, 두 비트 값이 모두 ‘1’ 이 아니면 비트의 값은 ‘0’ 이라 return합니다. 그리고 파이썬에서 숫자 ‘0’ 은 False를 의미합니다.
이진수의 ''&" 연산 살펴보기 🔍
- 5와 3의 이진수 연산 예시
- 5의 이진수는 101
- 3의 이진수는 011
- 비트별 AND 연산
- 이진수의 각 자리(비트) 별로 비교
- 첫번째 비트 : 1 & 0 == 0
- 두번째 비트 : 0 & 1 == 0
- 세번째 비트 : 1 & 1 == 1
- 비트별 and 연산 결과는 001 이며 이를 십진수로 하면 1이 됩니다.
- 따라서 5 & 3 연산의 결과는 int 인 ‘1’ 을 return하게 되고, 이것이 조건문에서는 True로 인식이 됩니다.
그래서 둘의 차이란게 뭔데…😥
- 돌고 돌아 비슷한 말들이 반복되지만 결국 핵심은 “둘다 ‘A’ 와 ‘B’ 를 비교하는데, 그 비교에 사용하는 값의 type이 다르다.” 는 것입니다.
- ‘and’ 연산자는 값 자체가 가지고 있는 논리적 진리성에 따라 A와 B를 비교해 True와 False를 판단하고 ‘&’ 연산자는 A의 비트 연산결과와 B의 비트연산결과를 ‘and’ 연산으로 한번 더 비교해서 True와 False를 판단하는 것입니다.
- 좀 더 확실한 이해를 위해 아래의 예제 코드를 살펴보겠습니다.
1
2
3
4
5
6
7
8
9
10
11
# and 연산자 예시
a = 4
b = 0
result = a and b # 여기서 b가 0이므로, 결과는 0이 됩니다.
# & 연산자 예시
a = 4 # 이진수로 100
b = 5 # 이진수로 101
result = a & b # 이진수로 100 & 101 = 100, 결과는 4가 됩니다.
-
이제 좀 어떤 차이인지 알 것 같습니다. 하지만 여전히 좀 이해가 안가는게 있습니다. 제가 배우면서 봤던 문제풀이에서의 이슈는 단순히 숫자의 비교가 아니라 다양한 조건식이 포함된 경우 였습니다.
-
그래서 이런 생각이 들 수 밖에 없었습니다. “이건 단순히 숫자연산인 경우이고… 다양한 변수간의 비교, 값에 대한 인덱싱 같은게 들어가는건 이렇게 이진화 할 수가 없는거 아닌가?”
-
맞습니다. ‘&’ 연산자는 결국 숫자의 비트 연산에 사용되는데, 숫자 이외의 형태인 데이터(문자열, 리스트, 딕셔너리 등)에는 ‘직접적으로 적용’ 되지는 않습니다.
👉 파이썬에서 다양한 연산자의 연산 순서를 알면 이해가 될 수 있습니다.
-
‘&’ 연산자는 숫자에 대해 적용되는데, 실제로 ‘&’ 연산자를 이런 데이터들에게 사용하면 작동이 잘만 됩니다. 왜일까요..?!
-
이는 ‘&’ 를 사용하기 위한 사전 연산 단계가 거쳐지기 때문입니다. 보통 우리가 조건문, 비교 표현식 등을 작성하면 단순히 변수 두개를 놓고 ‘A & B’ 형태로 쓰기도 하지만,
A[x] <= vx < 5 & B[y] >= 3
과 같은 식으로 다양한 변수에서 특정 값에 접근하는 형태로 사용하기도 합니다. -
이 경우 각 부분의 연산자로 인한 비교 결과(True or False)도출 한 뒤 그 값을 ‘이진수’ 로 변경하여 ‘&’ 연산을 사용합니다.
-
이러한 복합식에서의 ‘&’ 연산자에 대해 좀 더 톺아보기를 하면 좋을것 같습니다.
- 처음 제가 의문을 가지게 된 거북이 미로찾기 의 조건문을 가지고 비교해 보겠습니다.
- 제가 작성했던 코드는
if 0 <= nx < 5 and 0 <= ny < 5 and maze[nx][ny] == 0:
였는데 - 여기서 ‘and’를 ‘&’ 로 바꾸문 조건식 은 다음과 같습니다.
if 0 <= nx < 5 & 0 <= ny < 5 & maze[nx][ny] == 0:
- 여기서 nx와 ny는 2D 배열의 리스트(maze)에서 거북이가 이동할 좌표값입니다.
- 거북이가 있는 미로는 (4,4) 배열의 2D이기 때문에 0~4 사이의 미로 범위에서만 움직여야 하므로 이를 조건문으로 표현한 것입니다.
- 실제 로직에서는 막히거나(숫자1) 지나온길(숫자2) 여서 갈 수 없는 길인데 ‘&’ 조건문을 쓰면 거북이가 이동하는 현상이 발생합니다.
- 제가 작성했던 코드는
- 이제 파이썬에서 다양한 연산자들이 어떤 우선순위를 가지고 작동하는지를 살펴 보겠습니다.
파이썬에서의 연산자 작동순서
💡결론. 거북이 미로찾기로 본 조건문에서 ‘&’ 사용을 조심해야 하는 이유!
- 여기에는 크게 2가지 이유가 있습니다. ‘&’ 의 연산결과가 비트단위라는 것, 그리고 연산의 우선순위가 ‘and’ 조건보다 앞이라는 것 입니다.
- 비트 단위 연산`
- ‘&’ 연산자는 연산 대상들의 비트를 대상으로 ‘and’ 연산을 수행합니다. 이는 일반적인 논리연산자인 ‘and’와는 작동방식이 다릅니다.
- 보통 ‘and’ 는 표현식 전체의 논리적 True와 False를 평가합니다.
- 하지만 ‘&’ 는 연산대상의 ‘비트값’ 에 따라 결과를 결정 합니다.
- 특히 그 연산 대상이 ‘숫자’ 일때 예상치 못한 결과를 도출 할 수 있습니다.
- 연산 우선순위
- 위에서 정리했듯, 파이썬에서 ‘&’는 ‘and’ 연산자보다 높은 연산 우선순위를 갖습니다.
- 이는 표현식내에서 ‘&’가 다른 연산자와의 우선순위에서 적용되는 관계가 ‘and’ 와는 다르다는 것을 의미합니다.
-
위의 연산 순서를 실제 거북이 미로찾기에서
if 0 <= nx < 5 & 0 <= ny < 5 & maze[nx][ny] == 0:
에 적용하면 아래와 같은 순서로 풀이가 됩니다. - 1단계 : 비교연산자 우선순위 평가
- ‘&’ 연산자가 비교연산자 보다 우선순위가 높으므로 먼저 평가를 진행합니다.
nx < 5 & 0
과 같은 부분이 먼저 계산됩니다. 이는nx < 5
의 결과(비트 값으로 변환된)와0
의 비트 값을 AND 연산하는 것을 의미합니다.- 이 과정이
0 <= nx
와0 <= ny < 5
의 각 부분에서 진행됩니다.
- 2단계 : 비교연산자 평가
- 이제
0 <= nx
와0 <= ny
가 평가됩니다. 이는 단순 비교 연산으로, 각각의 값이 주어진 범위 내에 있는지 확인합니다.
- 3단계 : 마지막 조건 평가
maze[nx][ny] == 0
이 평가됩니다. 이는nx
와ny
가 가리키는maze
배열의 위치가 이동 가능한지(값이 0인지) 확인합니다.maze
는 2차원 배열이며, 이 배열의 각 요소는 미로의 특정 위치를 나타냅니다.- 여기서
0
은 “이동 가능한 위치”를 의미합니다.
- 4단계 : 최종결과 도출
- 1~3단계를 거쳐 모든 조건이 True인 경우,
if
문 내부의 코드들이 실행되고, 그렇지 않은 경우if
문을 건너뜁니다.
-
반면에 ‘and’ 조건으로 작성한
if 0 <= nx < 5 and 0 <= ny < 5 and maze[nx][ny] == 0:
를 사용했다면0 <= nx < 5
와0 <= ny < 5
가 각각 연산된 뒤에 두 값을 비교해 True/False를 비교한뒤, 그 결과와maze[nx][ny]
의 결과를 다시 and 연산으로 비교해서 True와 False를 판단 합니다. -
즉, 단순히 ‘&’와 ‘and’ 의 차이지만 연산을 하는 순서가 달라 예상치 못한 오류가 발생할 수 있습니다.
-
따라서 조건문(Conditional Statement) 에서는 반드시 ‘and’ 연산자를 사용해야 예상치 못한 연산오류 없이 원하는 결과를 얻을 수 있습니다.
🫡 Outro.
- 이번 포스팅에서는 ‘&’ 연산자와 ‘and’ 연산자가 조건문에서 어떻게 작용하는지, 왜 연산의 결과가 다른지 그 원인을 공부하여 정리했습니다.
- 단순한 질문에서 시작한 것이 의외로 심도 깊은 내용이어서 자료를 찾고 공부하는데 상당히 오래 걸리게 되었습니다.
- 그럼에도 흔히 할 수 있는 실수인 ‘&’ 연산자의 사용에 좀 더 경각심을 가질 수 있게 될 것 같고, 코드 작성에서 이런 부분을 고려해서 작성하게 될 수 있는 계기가 되어 오히려 다행이라 생각합니다.
댓글남기기