파이썬의 Boolean타입
파이썬에서는 True를 대체할 수 있는 다양한 수단이 존재한다. 예를 들어 이런 것들
numbers = map(int, input().split())
count = 0
while numbers:
numbers.pop()
count += 1
print(count)
numbers 배열의 길이가 0이 아니라면 while에 True로 전달된다.
또는 이런 것
k = 0
k = int(input())
if k:
print("k has been changed")
else:
print("k is still zero")
k의 값이 0이라면 if문에서 False로, 0이 아니라면 True로 전달된다. (정확히는 아님)
따라서 이런 표면적인 현상에 익숙해지면 이런 끔찍한 실수를 저지를 수 있는데 뭐냐면
True, False가 하나의 비트가 아닌데 비트처럼 생각해버린다는 것이다.
원인
파이썬에서 boolean 데이터는 1바이트의 크기를 갖는다. 여기에 하나의 비트로 True냐 False냐를 결정한다.
따져보면 이렇다.
True = 0000 0001
False = 0000 0000
그래서 boolean 데이터에 비트시프트를 걸면 다음과 같은 결과를 얻는다.
>>> t = True
>>> print(t<<1)
2
>>> f = False
>>> print(f<<1)
0
그럼 이제 True에 비트연산자 '~'을 쓰면 어떻게 되는가, True의 반전은 False이기 때문에 1에서 0으로 바뀌어야 할 것 같지만 모든 비트가 반전되기 때문에 결과는 이렇다.
~True = 1111 1110
~False = 1111 1111
여기다 비트시프트를 걸면 이런 결과를 얻는다.
>>> t = True
>>> f = False
>>> print(~t)
-2 # 1111 1110
>>> print(~f)
-1 # 1111 1111
>>> print(~t<<2)
-8 # 1111 1000
>>> print(~f<<2)
-4 # 1111 1100
하지만 비트연산자가 아닌 논리연산자인 not을 쓰면 결과는 달라진다.
>>> t = True
>>> f = False
>>> print(not t)
False
>>> print((not t)<<2)
0 # 0000 0000
>>> print((not f)<<2)
4 # 0000 0100
결론
어떤 변수의 값을 통해 True/False를 판별하려는 경우, 반전을 줄 때, 특별한 경우가 아니라면 비트연산자는 사용하지 않는 것이 좋다.
True/False 값의 안전한 반전은 not 연산자로 할 수 있다.