본문으로 바로가기
Lab

파이썬 연산자 종류와 헷갈리는 계산 규칙 정리

파이썬 3.15.0에서 나눗셈, 음수 몫과 나머지, 음수 거듭제곱, 같은 값과 같은 객체 비교, 0.1 + 0.2 비교를 직접 실행한 결과입니다. 파이썬 연산자에서 헷갈리는 출력이 왜 그렇게 나오는지 공식 문서를 바탕으로 짚습니다.

·

0 아래로 내려가는 계단과 거의 같은 무게의 이진 블록 더미를 단 저울을 그린 삽화
파이썬 연산자 종류와 헷갈리는 계산 규칙 정리 표지 삽화

파이썬에서 -7 // 2를 실행하면 -3이 아니라 -4가 나옵니다. 0.1 + 0.2는 0.30000000000000004로 찍히고, 0.1 + 0.2 == 0.3은 False예요. 이 글은 맥 한 대에서 파이썬 연산자 8단계를 한 번씩 실행한 기록입니다. AI 코딩 도구가 짜 준 코드에서 나눗셈이나 소수 비교가 이상하게 동작한다면 아래 결과와 맞춰 보세요.

파이썬 연산자 종류 한눈에 보기

종류대표 기호헷갈리는 결과
산술+ - * / // % **-7 // 2는 -4
비교== != > <1 < x < 5처럼 이어 쓸 수 있음
논리and or notnot x == 3은 괄호로 의도를 밝히는 편이 좋음
대입+= *= //= **=n //= 4는 몫만 남김
우선순위**, 단항 -, 괄호-2 ** 2는 -4
동일성is내용이 같은 리스트도 is는 False
멤버십in not in"py" in "python"은 True

함께 읽을 글

파이썬 나눗셈, 몫과 나머지는 어떻게 나올까요?

$ python3 - <<'PY'
print(7 + 2, 7 - 2, 7 * 2)
print(7 / 2, 7 // 2, 7 % 2, 2 ** 10)
print(-7 // 2, -7 % 2)
PY
9 5 14
3.5 3 1 1024
-4 1

/는 정수끼리 나눠도 3.5처럼 소수까지 돌려주고, //는 몫 3, %는 나머지 1을 돌려줍니다. 2 ** 10은 거듭제곱이라 1024가 나왔죠. 여기까지는 예상대로입니다.

그런데 음수가 들어가면 달라집니다. -7 // 2는 0 쪽으로 잘라 낸 -3이 아니라 아래쪽으로 내린 -4가 됐고, 짝을 이루는 -7 % 2는 1이 나왔어요. 금액을 나누거나 오프셋을 계산하는 코드에 음수가 들어올 수 있다면, AI가 쓴 //와 %가 이 결과를 전제로 짜였는지부터 확인해 보세요.

7 / 2는 3.5, 7 // 2는 3, -7 // 2는 -4, -2 ** 2는 -4, 0.1 + 0.2 == 0.3은 False인 실행 결과 표
직접 실행하면 -7 // 2는 -4, -2 ** 2는 -4가 나옵니다.
도식출처: 직접 실행한 순서

비교를 이어 쓰면 어떻게 되나요?

$ python3 - <<'PY'
x = 3
print(x == 3, x != 3, x > 1)
print(x > 1 and x < 5, x < 1 or x > 2, not x == 3)
print(1 < x < 5)
PY
True False True
True True False
True

x가 3일 때 x > 1 and x < 5는 True, x < 1 or x > 2도 오른쪽 조건이 맞으니 True입니다. not x == 3은 False가 나왔어요. 다만 (not x) == 3도 False라서 이 출력만으로는 not이 어디에 붙었는지 알 수 없습니다. 의도를 분명히 하려면 not (x == 3)이나 x != 3으로 쓰는 편이 좋습니다.

마지막 줄의 1 < x < 5도 True가 나왔습니다. 수학 식처럼 범위를 한 번에 쓸 수 있어서, 같은 출력을 내는 x > 1 and x < 5보다 읽기 쉽습니다.

복합 대입은 값이 어떻게 바뀌나요?

$ python3 - <<'PY'
n = 10
n += 5; print(n)
n *= 2; print(n)
n //= 4; print(n)
n **= 2; print(n)
PY
15
30
7
49

10에서 시작해 15, 30, 7, 49로 바뀌었습니다. n //= 4는 n = n // 4처럼 몫만 남기므로 7이 됐어요. n //= 4는 n = n // 4와 같은 계산이라, n이 음수라면 앞 절처럼 아래쪽으로 내린 값이 나올 것입니다(이번에는 양수만 실행했습니다).

음수 거듭제곱이 헷갈리는 이유

$ python3 - <<'PY'
print(2 + 3 * 4, (2 + 3) * 4)
print(-2 ** 2, (-2) ** 2)
print(2 ** 3 ** 2)
PY
14 20
-4 4
512

곱셈이 덧셈보다 먼저라서 2 + 3 * 4는 14, 괄호를 친 쪽은 20입니다. 여기까지는 익숙하죠. 그런데 -2 ** 2는 왜 4가 아니라 -4일까요?

공식 문서의 표현식 장에 따르면 -3 같은 음수는 문법상 리터럴이 아니라 - 연산자를 붙인 단항 연산입니다. 실행 결과를 보면 **가 단항 -보다 먼저 계산돼 -(2 ** 2)가 된 셈이고, (-2) ** 2처럼 괄호로 묶어야 4가 나왔어요. 2 ** 3 ** 2도 512가 나왔으니, 거듭제곱이 이어지는 식은 결과를 보고 판단하기보다 괄호로 의도를 적어 두는 편이 안전합니다.

문서도 괄호 묶음은 수학 표기처럼 우선순위를 바꾸거나 분명히 하려고 쓴다고 설명합니다. 혹시 AI 에이전트가 만든 수식에 음수와 **가 함께 있다면, 괄호가 있는지 한 번 더 보세요.

같은 값과 같은 객체는 어떻게 다를까요?

$ python3 - <<'PY'
a = [1, 2]
b = [1, 2]
print(a == b, a is b)
c = a
print(a is c)
value = None
print(value is None)
PY
True False
True
True

a와 b는 내용이 같아서 a == b는 True지만, 따로 만든 리스트라 a is b는 False입니다. 반면 c = a로 같은 리스트를 가리키게 하면 a is c가 True가 되죠. value is None도 True가 나왔습니다.

이럴 때는 숫자에 is를 써도 될까요? 공식 문서는 CPython에서 작은 정수는 같은 객체가 되지만 큰 정수는 다른 객체가 된다고 설명합니다. 이 동작은 앞으로 바뀔 수 있고, 리터럴과 is로 비교하면 CPython이 SyntaxWarning으로 ==를 쓰려던 게 아니냐고 묻습니다. 그러니 AI가 쓴 코드에 x is 7 같은 비교가 보이면 값 비교인 ==로 고치는 쪽이 맞습니다.

a == b는 True, a is b는 False, a is c는 True, value is None은 True인 결과를 정리한 표
같은 내용이라도 따로 만든 리스트는 is 비교에서 False가 나왔습니다
도식출처: 근거를 바탕으로 코드가 그린 도식

포함 여부는 어떻게 확인하나요?

$ python3 - <<'PY'
print("py" in "python", 3 in [1, 2, 3], "x" not in {"a": 1})
PY
True True True

in은 문자열 안의 부분 문자열, 리스트 안의 원소를 모두 확인했습니다. 딕셔너리 {"a": 1}에는 "x"가 없으니 not in이 True를 돌려줬어요. 세 경우 모두 같은 모양으로 쓸 수 있어서, 입력 검증 코드를 짧게 쓸 때 편합니다.

0.1과 0.2를 더하면 왜 0.3이 아닐까요?

$ python3 - <<'PY'
import math
print(0.1 + 0.2)
print(0.1 + 0.2 == 0.3)
print(math.isclose(0.1 + 0.2, 0.3))
PY
0.30000000000000004
False
True

공식 자습서의 부동 소수점 장은 이유를 이렇게 설명합니다. 부동 소수점 숫자는 하드웨어에서 밑이 2인 소수로 저장되는데, 십진수 0.1은 이진 소수로 정확히 표현할 수 없어요. 그래서 저장되는 값은 가장 가까운 근삿값이고, 파이썬은 그 값을 반올림해 보여 줄 뿐입니다.

이건 파이썬의 버그도, 여러분 코드의 버그도 아닙니다. 하드웨어 부동 소수점을 쓰는 모든 언어에서 같은 일이 생긴다고 문서는 말합니다. 대신 부정확한 값을 비교할 때는 math.isclose()가 유용할 수 있고, 실제로 이번 실행에서도 True가 나왔죠. 정확한 십진 표현이 필요한 회계 같은 용도에는 문서가 decimal 모듈을 권합니다.

십진수 0.1 블록이 이진 눈금 위 정확한 지점에 닿지 못하고 가까운 칸에 놓이는 개념 삽화
0.1이 가장 가까운 이진 근삿값으로 저장되는 원리를 그린 개념 그림입니다

그래서 결제 금액이나 할인율을 다루는 코드를 AI에게 맡겼다면, 소수끼리 ==로 비교하는 줄이 있는지 먼저 찾아보는 편이 좋습니다.

측정 조건과 한계

이 기록은 Homebrew로 설치돼 있던 python3(Python 3.15.0)를 쓰는 맥(darwin arm64) 한 대에서, 새 임시 폴더를 만들어 각 단계를 한 번씩만 실행한 결과입니다. 코드는 단계마다 python3 - <<'PY' ... PY 형태로 표준 입력에 넣었습니다.

  • 여덟 단계 모두 종료 코드 0으로 끝났고, 오류 메시지는 없었습니다.
  • 걸린 시간은 모두 0.0초로 기록돼 단계 간 속도 비교에는 쓸 수 없습니다.
  • 참고한 공식 문서는 3.15.2 문서이고, 실행한 파이썬은 3.15.0입니다.
  • 작은 정수의 객체 공유처럼 문서가 CPython 구현 상세라고 밝힌 동작은 다른 버전이나 구현에서 다를 수 있습니다.
  • 이 기록에는 AI가 생성한 코드나 답이 없습니다. AI가 작성한 코드도 위 예제처럼 실행해 기대한 출력과 비교해 보세요.

참고 자료