연산자와 표현식이란? 계산·비교·논리 연산의 동작 원리
연산자와 표현식이란? 계산·비교·논리 연산의 동작 원리#
변수에 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) # 3len(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) # True8을 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.1discount_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
True8_000 * 4는32_000입니다.- 수량 4개가 재고 3개보다 많아
quantity <= stock은 거짓입니다. - 하지만
is_preorder가 참이므로False or True는 참입니다. - 주문 금액은 30,000원 이상이므로 무료배송 조건도 참입니다.
이제 is_preorder = False로 바꾸어 보세요. 어떤 출력이 바뀌고, 어떤 출력은 그대로인지 설명할 수 있다면 산술·비교·논리 표현식의 역할을 구분한 것입니다.
정리#
연산자는 값에 적용할 작업을 나타내고, 표현식은 평가 결과로 값을 만듭니다.
- 산술 연산자는 가격, 수량, 합계 같은 값을 계산합니다.
- 비교 연산자는 두 값의 관계를 판단합니다.
- 논리 연산자는 여러 조건을 결합합니다.
- 할당은 표현식의 결과를 변수 이름으로 사용하게 합니다.
- 연산자 우선순위와 단락 평가는 어떤 부분이 먼저 실행되는지 결정합니다.
코드를 읽다가 결과가 예상과 다르다면 전체 줄을 한 번에 해석하려 하지 마세요. 각 표현식이 어떤 값을 만드는지, 그리고 그 값들이 어떤 순서로 결합되는지 하나씩 확인하는 것이 가장 빠른 출발점입니다.