Ch 3.1 산술·비교·논리 연산자
연산자는 데이터를 조작하고 비교하는 기본 도구입니다. 파이썬의 연산자는 직관적이고 강력합니다.
1. 산술 연산자
a = 17
b = 5
print(a + b) # 22 — 덧셈
print(a - b) # 12 — 뺄셈
print(a * b) # 85 — 곱셈
print(a / b) # 3.4 — 나눗셈 (항상 float 반환)
print(a // b) # 3 — 정수 나눗셈 (몫, 소수점 버림)
print(a % b) # 2 — 나머지 (모듈로)
print(a ** b) # 1419857 — 거듭제곱 (17^5)
# / 와 // 의 차이
print(7 / 2) # 3.5 (항상 float)
print(7 // 2) # 3 (정수 나눗셈)
print(-7 // 2) # -4 (음수는 더 작은 정수로 내림!)
# ** 연산자
print(2 ** 10) # 1024
print(2 ** 0.5) # 1.4142... (제곱근)
print(2 ** -1) # 0.5
수학 함수
import math
# math 모듈 활용
print(math.sqrt(16)) # 4.0 (제곱근)
print(math.floor(3.7)) # 3 (내림)
print(math.ceil(3.2)) # 4 (올림)
print(math.factorial(5)) # 120
print(math.log(100, 10)) # 2.0 (log10(100))
print(math.pi) # 3.141592653589793
# 내장 함수
print(abs(-42)) # 42 (절댓값)
print(round(3.14159, 2)) # 3.14
print(pow(2, 8)) # 256
quotient, remainder = divmod(17, 5) # (3, 2)
2. 비교 연산자
x = 10
y = 20
print(x == y) # False — 같음
print(x != y) # True — 다름
print(x < y) # True — 미만
print(x > y) # False — 초과
print(x <= y) # True — 이하
print(x >= y) # False — 이상
# 비교 연산자는 bool을 반환
result = x < y
print(type(result)) # <class 'bool'>
비교 연산자 체이닝
파이썬만의 특별한 기능 — 수학에서처럼 연속 비교가 가능합니다.
score = 75
# 파이썬에서만 가능한 체이닝 (다른 언어에서는 and 사용)
print(60 <= score < 80) # True (B 등급)
print(0 <= score <= 100) # True (유효 점수)
# 위와 동일한 표현
print(60 <= score and score < 80) # 더 장황함
# 실전 활용: 점수 등급 판별
def get_grade(score: int) -> str:
"""점수를 입력받아 등급을 반환합니다."""
if not 0 <= score <= 100:
raise ValueError(f"점수는 0~100 사이여야 합니다: {score}")
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
for s in [95, 85, 75, 65, 55]:
print(f"{s}점: {get_grade(s)}등급")
3. 논리 연산자
# and — 둘 다 True일 때 True
print(True and True) # True
print(True and False) # False
print(False and True) # False
# or — 하나라도 True면 True
print(True or False) # True
print(False or False) # False
# not — 반전
print(not True) # False
print(not False) # True
print(not 0) # True
print(not "") # True
단락 평가(Short-circuit Evaluation)
파이썬은 논리 연산에서 결과가 확정되면 나머지 표현식을 평가하지 않습니다.
# and: 첫 번째가 False면 두 번째 평가 안 함
def expensive_check():
print("비용이 큰 연산 실행!")
return True
result = False and expensive_check() # "비용이 큰 연산 실행!" 출력 안 됨
print(result) # False
# or: 첫 번째가 True면 두 번째 평가 안 함
result2 = True or expensive_check() # "비용이 큰 연산 실행!" 출력 안 됨
print(result2) # True
# 단락 평가를 이용한 안전한 접근
user = {"name": "Alice", "profile": {"age": 30}}
# 딕셔너리 키가 없을 때 안전하게 접근
profile = user.get("profile")
age = profile.get("age") if profile is not None else None
print(age) # 30
논리 연산자의 반환 값
파이썬의 논리 연산자는 True/False가 아닌 실제 값을 반환합니다.
# and — 첫 번째가 Falsy면 첫 번째, 아니면 두 번째 반환
print(0 and "hello") # 0 (첫 번째가 Falsy)
print("hello" and "world") # 'world' (첫 번째가 Truthy)
# or — 첫 번째가 Truthy면 첫 번째, 아니면 두 번째 반환
print(0 or "default") # 'default' (첫 번째가 Falsy)
print("value" or "default") # 'value' (첫 번째가 Truthy)
# 실용적인 기본값 패턴
config_value = None
name = config_value or "기본 이름"
print(name) # 기본 이름
# 단, 0, False, "" 등도 Falsy이므로 주의!
count = 0
result = count or 10 # 0을 의미 있는 값으로 쓴다면 문제!
print(result) # 10 (의도치 않은 결과)
# 더 안전한 방법: is None 검사
result = count if count is not None else 10
print(result) # 0 (올바른 결과)
4. 할당 연산자
x = 10
x += 5 # x = x + 5 → 15
x -= 3 # x = x - 3 → 12
x *= 2 # x = x * 2 → 24
x /= 4 # x = x / 4 → 6.0 (float!)
x //= 2 # x = x // 2 → 3.0
x **= 2 # x = x ** 2 → 9.0
x %= 4 # x = x % 4 → 1.0
# 문자열에도 사용 가능
text = "Hello"
text += ", World!"
print(text) # Hello, World!
# 리스트에도 사용 가능
items = [1, 2, 3]
items += [4, 5] # extend와 동일
print(items) # [1, 2, 3, 4, 5]
5. is vs == — 동일성 vs 동등성
# == — 값(value)이 같은지 비교 (동등성)
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True — 값이 같음
# is — 동일한 객체(같은 메모리 주소)인지 비교 (동일성)
print(a is b) # False — 서로 다른 객체
# 같은 객체를 참조하면 is도 True
c = a # c는 a와 같은 객체를 가리킴
print(a is c) # True
# id() 함수로 메모리 주소 확인
print(id(a), id(b), id(c))
# 예: 140234567890 140234567920 140234567890
# a와 c는 같은 주소, b는 다른 주소
작은 정수 캐싱 주의사항
# 파이썬은 -5 ~ 256 범위의 정수를 캐싱함
a = 100
b = 100
print(a is b) # True (캐싱된 객체 공유)
# 257 이상은 캐싱되지 않음
x = 1000
y = 1000
print(x is y) # False (인터프리터 구현에 따라 다를 수 있음)
print(x == y) # True (값은 같음)
# 결론: 정수 비교에는 항상 == 사용, is는 None/True/False 비교에만 사용
print(None is None) # True (권장)
print(True is True) # True
6. 멤버십 연산자 — in, not in
fruits = ["apple", "banana", "cherry"]
print("apple" in fruits) # True
print("grape" in fruits) # False
print("grape" not in fruits) # True
# 문자열에서도 사용 가능
text = "Hello, Python!"
print("Python" in text) # True
print("Java" not in text) # True
# 딕셔너리에서는 키를 검색
config = {"host": "localhost", "port": 5432}
print("host" in config) # True (키 검색)
print("localhost" in config) # False (값은 검색 안 됨!)
print("localhost" in config.values()) # True (값 검색)
7. 실전 예제
짝수/홀수 판별
def classify_number(n: int) -> str:
if n % 2 == 0:
return f"{n}은 짝수입니다."
else:
return f"{n}은 홀수입니다."
for i in range(1, 8):
print(classify_number(i))
점수 등급 계산 (실전 버전)
def calculate_grade(score: int) -> dict[str, str]:
"""점수를 받아 등급, 통과 여부, 메시지를 반환합니다."""
if not 0 <= score <= 100:
raise ValueError(f"유효하지 않은 점수: {score}")
passed = score >= 60
grade = (
"A" if score >= 90
else "B" if score >= 80
else "C" if score >= 70
else "D" if score >= 60
else "F"
)
message = "합격" if passed else "불합격"
return {"grade": grade, "passed": str(passed), "message": message}
print(calculate_grade(95)) # {'grade': 'A', 'passed': 'True', 'message': '합격'}
print(calculate_grade(45)) # {'grade': 'F', 'passed': 'False', 'message': '불합격'}
윤년 판별
def is_leap_year(year: int) -> bool:
"""윤년 여부를 반환합니다.
윤년 조건:
1. 4로 나누어 떨어지고
2. 100으로 나누어 떨어지지 않거나
3. 400으로 나누어 떨어진다
"""
return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
test_years = [1900, 2000, 2024, 2100, 2400]
for y in test_years:
print(f"{y}년: {'윤년' if is_leap_year(y) else '평년'}")
# 출력:
# 1900년: 평년 (100의 배수이지만 400의 배수 아님)
# 2000년: 윤년 (400의 배수)
# 2024년: 윤년 (4의 배수이고 100의 배수 아님)
# 2100년: 평년 (100의 배수이지만 400의 배수 아님)
# 2400년: 윤년 (400의 배수)
고수 팁:
and/or 단락 평가로 안전한 기본값 패턴# 패턴 1: or로 기본값 설정
# (단, Falsy 값 — 0, [], "" 등 — 이 의미 있을 때는 사용 주의)
def get_config(key: str, default: str) -> str:
env_value = None # 환경변수 없는 경우 시뮬레이션
return env_value or default
print(get_config("DB_HOST", "localhost")) # localhost
# 패턴 2: and로 None 안전 체인 접근
user = {"profile": {"address": {"city": "Seoul"}}}
# 안전하지 않음:
# city = user["profile"]["address"]["city"] # KeyError 위험
# and를 활용한 안전한 체인 접근
profile = user.get("profile")
address = profile and profile.get("address")
city = address and address.get("city")
print(city) # Seoul
# Python 3.10+ walrus 연산자로 더 간결하게 (Ch 3.4에서 상세 설명)
if (profile := user.get("profile")) and (addr := profile.get("address")):
city = addr.get("city", "Unknown")
print(f"도시: {city}")
# 패턴 3: 조건부 함수 호출
import os
debug_mode = os.environ.get("DEBUG", "false").lower() == "true"
debug_mode and print("디버그 모드 활성화") # debug_mode가 True일 때만 실행
산술, 비교, 논리 연산자를 모두 익혔습니다. 다음 챕터에서는 비트 연산자와 특수 연산자를 살펴보겠습니다.