연산자와 표현식이란? 계산·비교·논리 연산의 동작 원리

연산자와 표현식이란? 계산·비교·논리 연산의 동작 원리#

변수에 price = 10_000처럼 값을 저장했다면, 이제 그 값으로 계산하고 판단해야 합니다.

total = price * quantity
is_free_shipping = total >= 30_000

첫 번째 줄은 가격과 수량을 계산합니다. 두 번째 줄은 계산 결과가 무료배송 기준을 충족하는지 비교합니다. 이때 *와 >=처럼 값에 작업을 적용하는 기호가 연산자입니다. price * quantity처럼 실행 결과로 하나의 값이 만들어지는 코드가 표현식입니다.

연산자와 표현식을 이해하면 조건문에 무엇을 넣어야 하는지, 계산 결과가 왜 예상과 달라졌는지, =와 ==가 왜 다른지 설명할 수 있습니다. 이 글에서는 Python으로 예제를 보여주되, 계산·비교·판단이라는 개념은 여러 프로그래밍 언어에 공통으로 적용됩니다.

먼저 구분하는 세 가지 용어#

total = price * quantity
구성 예시 역할
피연산자 price, quantity 연산에 사용되는 값
연산자 * 값에 적용할 작업을 나타냄
표현식 price * quantity 평가하면 결과값이 만들어짐

price * quantity의 결과가 30_000이라면, 할당문은 그 결과를 total이라는 이름으로 사용할 수 있게 합니다.

표현식은 값을 만들고, 변수는 그 값을 이후 코드에서 사용할 수 있게 합니다.

표현식은 어떻게 값을 만들까?#

표현식은 평가했을 때 결과를 얻을 수 있는 코드입니다. 숫자 하나나 변수 이름도 표현식이 될 수 있고, 여러 연산을 결합할 수도 있습니다.

10                 # 결과값: 10
price              # price에 연결된 값
price * quantity   # 곱셈 결과
total >= 30_000    # 비교 결과: True 또는 False

함수 호출도 값을 반환한다면 표현식으로 사용할 수 있습니다.

name = "Kim"

length = len(name)

print(length)  # 3

len(name)을 평가한 결과인 3이 length에 할당됩니다.

표현식과 문장은 무엇이 다를까?#

입문 단계에서는 다음 정도로 구분하면 충분합니다.

  • 표현식: 평가하면 값이 됩니다. 예: price * 2
  • 문장: 프로그램에 어떤 작업을 지시합니다. 예: if문, for문, 할당문
discount = price * 0.1

여기서 price * 0.1은 표현식이고, 한 줄 전체는 계산한 값을 discount에 할당하는 문장입니다.

Python에서는 다른 언어와 달리 일반적인 할당문 = 자체를 값처럼 사용할 수 없습니다. 따라서 다음 코드는 실행되지 않습니다.

# Python에서는 문법 오류
# result = (total = price * quantity)

여러 언어를 배울 때는 같은 기호라도 표현식으로 사용할 수 있는 범위가 언어마다 다를 수 있다는 점을 기억하세요.

산술 연산자: 숫자를 계산하기#

산술 연산자는 숫자의 합계, 차이, 곱, 나눗셈 등을 계산합니다.

연산자 의미 예시 Python에서의 결과
+ 덧셈 10 + 3 13
- 뺄셈 10 - 3 7
* 곱셈 10 * 3 30
/ 나눗셈 10 / 3 3.333...
// 몫을 구하는 나눗셈 10 // 3 3
% 나머지 10 % 3 1
** 거듭제곱 2 ** 3 8

예를 들어 상품 금액은 가격과 수량을 곱해 구합니다.

price = 3_000
quantity = 4

total = price * quantity

print(total)  # 12000

숫자 안의 밑줄은 큰 수를 읽기 쉽게 하기 위한 Python 표기입니다. 3_000은 3000과 같은 숫자입니다.

/와 //는 어떻게 다를까?#

print(10 / 3)   # 3.3333333333333335
print(10 // 3)  # 3

/는 나눗셈 결과를 반환하며, Python에서는 정수끼리 나누더라도 결과가 부동소수점 수입니다.

//는 내림 나눗셈입니다. 양수끼리 계산할 때는 흔히 소수 부분을 버린 몫처럼 보이지만, 음수가 들어가면 단순히 “소수 부분 제거”라고 이해하면 틀릴 수 있습니다.

print(-10 // 3)  # -4

-10 / 3은 약 -3.33이고, 이를 더 작은 정수 쪽으로 내리면 -4입니다. Python의 //를 사용할 때 이 차이를 알아두면 음수 계산에서 실수를 줄일 수 있습니다.

%는 어디에 쓸까?#

나머지 연산은 짝수 판단에 자주 사용합니다.

number = 8

is_even = number % 2 == 0

print(is_even)  # True

8을 2로 나눈 나머지는 0이므로 is_even에 True가 들어갑니다.

나머지 연산은 번호를 일정한 간격으로 분류할 때도 쓸 수 있습니다.

sequence = 7

group_number = sequence % 3

print(group_number)  # 1

단, 업무에서 순환 번호나 인덱스를 설계할 때는 0부터 시작하는 결과가 필요한지 먼저 정해야 합니다.

0으로 나누면 어떻게 될까?#

count = 0

# average = total / count
# 실행하면 ZeroDivisionError가 발생한다.

문법은 맞지만 실행 중 0으로 나눌 수 없어 예외가 발생합니다. 평균처럼 나눗셈이 필요한 계산에서는 분모가 0이 될 수 있는 상황을 고려해야 합니다.

scores = []

if len(scores) == 0:
    print("계산할 점수가 없습니다.")
else:
    average = sum(scores) / len(scores)
    print(average)

빈 목록의 평균을 0으로 표시할지, 값이 없다고 표시할지는 서비스의 규칙에 따라 정해야 합니다.

문자열에서도 연산자를 사용할까?#

같은 연산자가 자료형에 따라 다른 의미로 쓰일 수 있습니다. Python에서 +는 숫자를 더할 수도 있고 문자열을 이어 붙일 수도 있습니다.

print(10 + 10)       # 20
print("10" + "10")   # 1010

둘째 결과는 숫자 1010이 아니라 문자열 "1010"입니다.

first_name = "길동"
last_name = "홍"

full_name = last_name + first_name

print(full_name)  # 홍길동

문자열은 *로 정해진 횟수만큼 반복할 수도 있습니다.

print("-" * 5)  # -----

그러나 모든 자료형 조합이 허용되는 것은 아닙니다.

price_text = "10000"

# print(price_text + 5000)
# TypeError: 문자열과 정수를 그대로 더할 수 없다.

숫자로 계산하려면 먼저 의도에 맞게 변환해야 합니다.

price = int(price_text)
total = price + 5000

print(total)  # 15000

실제 사용자 입력을 변환할 때는 "만원" 같은 값이 들어와 ValueError가 발생할 가능성도 고려해야 합니다.

비교 연산자: 두 값을 비교하기#

비교 연산자는 두 값의 관계를 판단하고 보통 True 또는 False를 반환합니다. 이 값은 조건문의 실행 여부를 결정할 때 사용됩니다.

연산자 의미 예시 결과
== 같은 값인가 10 == 10 True
!= 다른 값인가 10 != 5 True
> 더 큰가 10 > 5 True
< 더 작은가 10 < 5 False
>= 크거나 같은가 10 >= 10 True
<= 작거나 같은가 10 <= 5 False

무료배송 기준을 판단해 보겠습니다.

order_total = 34_000

is_free_shipping = order_total >= 30_000

print(is_free_shipping)  # True

같은 비교식을 조건문에 직접 넣을 수도 있습니다.

if order_total >= 30_000:
    print("무료배송 대상입니다.")

=와 ==는 완전히 다르다#

status = "paid"

=는 오른쪽 값을 왼쪽 이름에 할당합니다.

is_paid = status == "paid"

==는 두 값이 같은지 비교합니다. 이 표현식의 결과는 True 또는 False입니다.

이 차이를 모르고 if문에 다음처럼 적으면 Python에서는 문법 오류가 발생합니다.

# 잘못된 코드
# if status = "paid":
#     print("결제 완료")

올바른 비교는 ==를 사용합니다.

if status == "paid":
    print("결제 완료")

연속 비교도 가능하다#

Python에서는 범위를 다음처럼 표현할 수 있습니다.

score = 85

if 0 <= score <= 100:
    print("유효한 점수입니다.")

뜻은 “점수가 0 이상이고 100 이하인가?”입니다. 수학에서 범위를 적는 방식과 비슷하지만, 다른 언어에서 같은 문법이 그대로 동작한다고 가정해서는 안 됩니다.

문자열 비교는 숫자 비교와 다르다#

print("100" > "20")  # False

두 값은 숫자가 아니라 문자열입니다. 문자열은 문자들의 순서에 따라 비교되므로, 숫자의 크기를 비교하려면 숫자로 변환해야 합니다.

print(int("100") > int("20"))  # True

상품 가격이나 수량이 외부에서 문자열로 들어온다면 비교 전에 자료형을 확인해야 합니다.

논리 연산자: 여러 조건을 결합하기#

하나의 비교로는 판단하기 어려운 상황이 많습니다. 예를 들어 주문을 출고하려면 결제가 끝났고 재고도 있어야 합니다.

Python에서는 and, or, not으로 조건을 결합합니다.

연산자 의미 참이 되는 조건
and 두 조건을 모두 만족하는가 양쪽이 모두 참
or 둘 중 하나 이상 만족하는가 적어도 하나가 참
not 결과를 뒤집는가 대상이 거짓

and: 두 조건이 모두 참이어야 할 때#

is_paid = True
has_stock = False

can_ship = is_paid and has_stock

print(can_ship)  # False

결제가 완료되어도 재고가 없으므로 출고할 수 없습니다.

if is_paid and has_stock:
    print("출고를 진행합니다.")
else:
    print("결제 상태 또는 재고를 확인해야 합니다.")

or: 어느 한쪽만 충족해도 될 때#

is_admin = False
is_order_owner = True

can_view_order = is_admin or is_order_owner

print(can_view_order)  # True

관리자이거나 주문자 본인이면 주문을 볼 수 있다는 단순화된 예입니다. 실제 접근 권한은 인증과 소유 관계를 안전하게 확인하는 별도 로직이 필요합니다.

not: 조건을 뒤집을 때#

is_closed = False

if not is_closed:
    print("신청할 수 있습니다.")

not is_closed는 “마감되지 않았는가?”를 뜻합니다.

조건을 읽을 때 이중 부정이 많아지면 뜻을 파악하기 어렵습니다.

# 뜻은 같지만 읽기 어렵다.
# if not is_not_available:

조건을 표현하는 변수 이름도 코드의 가독성에 영향을 줍니다.

단락 평가: 모든 조건을 항상 검사하지는 않는다#

논리 연산에서 중요한 특징은 필요한 만큼만 평가한다는 점입니다. 이를 단락 평가라고 합니다.

and는 앞이 거짓이면 뒤를 볼 필요가 없다#

scores = []

if len(scores) > 0 and sum(scores) / len(scores) >= 80:
    print("평균 80점 이상입니다.")

scores가 비어 있으므로 len(scores) > 0은 거짓입니다. and는 양쪽이 모두 참이어야 하므로 뒤쪽 나눗셈을 평가하지 않습니다. 그 결과 이 예제에서는 0으로 나누는 오류가 발생하지 않습니다.

하지만 조건의 순서를 바꾸면 문제가 생깁니다.

# 빈 목록에서는 앞쪽 나눗셈부터 실행되어 오류가 발생한다.
# if sum(scores) / len(scores) >= 80 and len(scores) > 0:
#     ...

같은 조건이라도 평가 순서가 안전성에 영향을 줄 수 있습니다.

or는 앞이 참이면 뒤를 볼 필요가 없다#

is_admin = True

if is_admin or check_order_owner():
    print("주문을 볼 수 있습니다.")

is_admin이 True라면 check_order_owner()는 호출되지 않습니다. 여기서 check_order_owner()는 소유 여부를 확인하는 함수가 있다고 가정한 예입니다.

검사 함수를 반드시 실행해야 하는 작업이 포함되어 있다면, or의 뒤에 놓았을 때 호출되지 않을 수 있다는 점을 알아야 합니다.

Python에서는 and와 or가 항상 불리언만 반환할까?#

아닙니다. 조건문 예제에서는 True와 False를 다뤘지만, Python의 and와 or는 피연산자 중 하나를 그대로 반환할 수 있습니다.

display_name = "" or "이름 없음"

print(display_name)  # 이름 없음

빈 문자열은 조건에서 거짓으로 취급되므로 or 뒤의 문자열이 결과가 됩니다.

이런 코드는 편리하지만 처음에는 논리 연산의 결과가 언제나 bool이라고 가정하지 않는 것이 중요합니다.

참과 거짓으로 판단되는 값#

Python의 if에는 꼭 True나 False 변수만 넣어야 하는 것은 아닙니다. 빈 문자열이나 빈 리스트처럼 조건에서 거짓으로 판단되는 값도 있습니다.

name = ""

if name:
    print(f"안녕하세요, {name}님!")
else:
    print("이름을 입력해 주세요.")

여기서 빈 문자열 ""은 거짓으로 판단됩니다.

값 조건에서의 판단
False 거짓
None 거짓
숫자 0 거짓
빈 문자열 "" 거짓
빈 리스트 [] 거짓
숫자 1 참
문자열 "0" 참
항목이 있는 리스트 참

특히 문자열 "0"은 숫자 0과 다릅니다. 글자 하나가 들어 있는 문자열이므로 참으로 판단됩니다.

print(bool(0))    # False
print(bool("0"))  # True

실무에서는 값이 없다는 뜻의 None과 숫자 0이 서로 다른 의미일 수 있습니다. 그럴 때는 if value:로 한꺼번에 판단하지 말고 의도를 명시합니다.

discount = 0

if discount is None:
    print("할인 정보가 없습니다.")
else:
    print(f"할인 금액: {discount}원")

0원 할인은 “정보가 없는 상태”가 아닙니다.

할당 연산: 계산 결과를 변수에 반영하기#

처음 보는 할당은 다음 형태입니다.

total = 10_000

오른쪽의 값이나 표현식을 계산한 뒤 왼쪽 변수에 연결합니다.

price = 3_000
quantity = 4

total = price * quantity

print(total)  # 12000

변수의 현재 값을 사용해 새 값을 할당할 수도 있습니다.

count = 0

count = count + 1

print(count)  # 1

오른쪽의 count + 1을 먼저 계산합니다. 현재 값이 0이므로 결과는 1입니다. 그다음 count에 1을 다시 할당합니다.

수학의 등식처럼 “count와 count + 1이 항상 같다”는 뜻이 아닙니다.

복합 할당 연산자#

자주 쓰는 변경은 짧게 적을 수 있습니다.

count += 1       # count = count + 1
total -= 3_000   # total = total - 3_000
price *= 2       # price = price * 2

반복문에서 합계를 누적할 때 흔히 사용합니다.

prices = [3_000, 5_000, 2_000]
total = 0

for price in prices:
    total += price

print(total)  # 10000

초보자에게는 먼저 total = total + price로 읽고, 익숙해지면 += 형태를 사용해도 좋습니다.

연산자 우선순위: 어떤 계산이 먼저 실행될까?#

여러 연산자가 한 표현식에 들어 있으면 계산 순서가 중요합니다.

result = 2 + 3 * 4

print(result)  # 14

곱셈이 덧셈보다 먼저 수행되므로 3 * 4가 12이고, 여기에 2를 더합니다.

먼저 더하고 싶다면 괄호를 사용합니다.

result = (2 + 3) * 4

print(result)  # 20

자주 만나는 우선순위#

아래로 갈수록 일반적으로 나중에 평가됩니다.

우선순위 예시 설명
높은 편 ( ) 괄호 안을 먼저 평가
** 거듭제곱
*, /, //, % 곱셈과 나눗셈 계열
+, - 덧셈과 뺄셈
==, !=, <, <=, >, >= 비교
not 논리 부정
and 논리곱
낮은 편 or 논리합

이 표는 입문 단계에서 자주 쓰는 표현식을 읽기 위한 요약입니다. 세부 우선순위를 모두 외우기보다, 여러 연산이 섞여 뜻이 불분명해지면 괄호로 의도를 표시하는 편이 안전합니다.

is_paid = True
has_stock = False
is_preorder = True

can_accept = is_paid and (has_stock or is_preorder)

print(can_accept)  # True

결제가 완료되었고, 재고가 있거나 예약 주문이 가능한 경우에만 접수한다는 뜻이 괄호 덕분에 분명해집니다.

괄호가 많다고 무조건 읽기 쉬운 것은 아니다#

긴 조건식을 한 줄에 쌓기보다 의미 있는 중간값으로 나누는 방법도 있습니다.

has_available_option = has_stock or is_preorder
can_accept = is_paid and has_available_option

이렇게 하면 어떤 판단을 먼저 하는지 변수 이름으로 설명할 수 있습니다.

==와 is: 값 비교와 객체 동일성의 차이#

Python을 쓰다 보면 ==와 is를 모두 보게 됩니다. 두 연산자는 용도가 다릅니다.

  • ==: 두 값이 같은지 비교합니다.
  • is: 두 이름이 정확히 같은 객체를 가리키는지 비교합니다.
first = [1, 2]
second = [1, 2]

print(first == second)  # True
print(first is second)  # False

두 리스트의 내용은 같습니다. 하지만 각각 따로 만든 리스트 객체입니다.

값이 같은지 확인할 때는 일반적으로 ==를 사용합니다.

status = "paid"

if status == "paid":
    print("결제 완료")

None인지 검사할 때는 is None을 사용합니다.

result = None

if result is None:
    print("결과가 없습니다.")

숫자나 문자열의 값을 비교하려고 is를 사용하지 마세요. 객체가 우연히 재사용되는 구현 세부사항 때문에 어떤 상황에서는 참처럼 보일 수 있어도, 값 비교의 뜻을 나타내는 연산자는 ==입니다.

포함 여부 검사: in과 not in#

특정 값이 문자열이나 목록 등에 들어 있는지 확인할 때는 in을 사용합니다.

allowed_roles = ["admin", "editor", "viewer"]
role = "editor"

print(role in allowed_roles)      # True
print(role not in allowed_roles)  # False

문자열에서도 사용할 수 있습니다.

message = "주문이 완료되었습니다."

if "완료" in message:
    print("완료 안내 문구가 있습니다.")

이 검사는 단순히 글자가 포함되어 있는지를 확인합니다. 실제 주문이 완료되었는지를 판단하려면 안내 문구가 아니라 주문의 상태 데이터를 검사해야 합니다.

order_status = "completed"

if order_status == "completed":
    print("완료된 주문입니다.")

표현식이 기술적으로 참이라는 사실과 업무적으로 올바른 판단이라는 사실은 다를 수 있습니다.

실무 예제: 주문 가능 여부와 결제 금액 계산하기#

지금까지 살펴본 연산자를 하나의 짧은 예제에 적용해 보겠습니다.

주문 조건은 다음과 같습니다.

  • 상품 가격은 12,000원이고 수량은 3개입니다.
  • 재고는 5개입니다.
  • 주문 금액이 30,000원 이상이면 무료배송입니다.
  • 재고가 충분하고 결제 수단이 선택되어야 주문을 진행할 수 있습니다.
price = 12_000
quantity = 3
stock = 5
payment_method = "card"

subtotal = price * quantity
has_stock = quantity <= stock
has_payment_method = payment_method != ""
can_order = has_stock and has_payment_method
is_free_shipping = subtotal >= 30_000

print(f"상품 금액: {subtotal}원")
print(f"재고 충분: {has_stock}")
print(f"결제 수단 선택: {has_payment_method}")
print(f"주문 가능: {can_order}")
print(f"무료배송 대상: {is_free_shipping}")

실행 결과:

상품 금액: 36000원
재고 충분: True
결제 수단 선택: True
주문 가능: True
무료배송 대상: True

각 줄이 맡은 일을 살펴보면 다음과 같습니다.

표현식 결과 판단
price * quantity 36000 상품 금액 계산
quantity <= stock True 필요한 수량만큼 재고가 있는가?
payment_method != "" True 결제 수단이 비어 있지 않은가?
has_stock and has_payment_method True 두 주문 조건을 모두 충족하는가?
subtotal >= 30_000 True 무료배송 기준을 충족하는가?

이 예제는 연산자의 동작을 보여주기 위한 것입니다. 실제 주문 시스템에서는 결제 수단의 유효성, 동시 주문에 따른 재고 변경, 배송 지역과 요금 등 더 많은 조건을 확인해야 합니다.

처음 배울 때 자주 하는 실수#

숫자와 문자열을 같은 값으로 생각하기#

quantity_text = "3"

# print(quantity_text + 2)  # TypeError

사용자 입력은 문자열로 들어올 수 있습니다. 계산하려면 숫자로 변환해야 합니다.

quantity = int(quantity_text)
print(quantity + 2)  # 5

/와 //를 혼동하기#

discount_rate = 10 / 100
print(discount_rate)  # 0.1
discount_rate = 10 // 100
print(discount_rate)  # 0

할인율 10%를 계산하려는 상황에서 //를 사용하면 결과가 0이 됩니다. 문법 오류가 발생하지 않으므로 결과를 직접 확인해야 발견할 수 있습니다.

범위 조건의 순서를 잘못 작성하기#

score = 85

if score >= 60:
    grade = "D"
elif score >= 80:
    grade = "B"

print(grade)  # D

비교 연산자 자체는 올바르지만, 첫 조건이 85점에도 해당하므로 뒤의 조건은 확인하지 않습니다. 표현식의 결과와 조건문의 평가 순서를 함께 살펴봐야 합니다.

진릿값 검사로 0과 값 없음 구분을 잃기#

discount = 0

if not discount:
    print("할인 정보가 없습니다.")

0도 거짓으로 판단되므로 이 출력은 “할인 금액이 0원”이라는 정상 상태를 “정보 없음”으로 잘못 해석할 수 있습니다. 값이 없음을 None으로 표현했다면 다음처럼 검사합니다.

if discount is None:
    print("할인 정보가 없습니다.")

직접 확인해 보기#

아래 코드의 출력값을 실행 전에 먼저 예상해 보세요.

price = 8_000
quantity = 4
stock = 3
is_preorder = True

total = price * quantity
can_accept = (quantity <= stock) or is_preorder
is_free_shipping = total >= 30_000

print(total)
print(can_accept)
print(is_free_shipping)

정답은 다음과 같습니다.

32000
True
True
  • 8_000 * 4는 32_000입니다.
  • 수량 4개가 재고 3개보다 많아 quantity <= stock은 거짓입니다.
  • 하지만 is_preorder가 참이므로 False or True는 참입니다.
  • 주문 금액은 30,000원 이상이므로 무료배송 조건도 참입니다.

이제 is_preorder = False로 바꾸어 보세요. 어떤 출력이 바뀌고, 어떤 출력은 그대로인지 설명할 수 있다면 산술·비교·논리 표현식의 역할을 구분한 것입니다.

정리#

연산자는 값에 적용할 작업을 나타내고, 표현식은 평가 결과로 값을 만듭니다.

  • 산술 연산자는 가격, 수량, 합계 같은 값을 계산합니다.
  • 비교 연산자는 두 값의 관계를 판단합니다.
  • 논리 연산자는 여러 조건을 결합합니다.
  • 할당은 표현식의 결과를 변수 이름으로 사용하게 합니다.
  • 연산자 우선순위와 단락 평가는 어떤 부분이 먼저 실행되는지 결정합니다.

코드를 읽다가 결과가 예상과 다르다면 전체 줄을 한 번에 해석하려 하지 마세요. 각 표현식이 어떤 값을 만드는지, 그리고 그 값들이 어떤 순서로 결합되는지 하나씩 확인하는 것이 가장 빠른 출발점입니다.

이 페이지의 목차