본문으로 건너뛰기
Advertisement

Ch 3.4 조건 표현식과 Walrus 연산자

파이썬의 조건 표현식(삼항 연산자)과 Walrus 연산자(:=)는 코드를 더 간결하게 만드는 강력한 도구입니다. 단, 가독성을 해치지 않는 범위에서 사용해야 합니다.

1. 조건 표현식 (삼항 연산자)

파이썬의 삼항 연산자는 if-else한 줄 표현식으로 압축합니다.

# 기본 구문
# value_if_true if condition else value_if_false

x = 10
result = "양수" if x > 0 else "음수 또는 0"
print(result) # 양수

# 비교: 일반 if-else
if x > 0:
result = "양수"
else:
result = "음수 또는 0"

# 다양한 활용 예시
age = 20
label = "성인" if age >= 18 else "미성년자"
print(label) # 성인

score = 75
grade = "합격" if score >= 60 else "불합격"
print(grade) # 합격

# 함수 반환값에 활용
def abs_value(n: int) -> int:
return n if n >= 0 else -n

print(abs_value(-5)) # 5
print(abs_value(3)) # 3

# 변수 대입이 아닌 표현식으로도 사용
numbers = [1, -2, 3, -4, 5]
abs_numbers = [n if n >= 0 else -n for n in numbers]
print(abs_numbers) # [1, 2, 3, 4, 5]

실전 예제

from datetime import datetime

# 현재 시간에 따른 인사말
def get_greeting() -> str:
hour = datetime.now().hour
return (
"좋은 아침이에요!" if hour < 12
else "좋은 오후예요!" if hour < 17
else "좋은 저녁이에요!" if hour < 22
else "늦은 밤이네요!"
)

print(get_greeting())

# None 처리
def format_phone(phone: str | None) -> str:
return phone if phone is not None else "번호 없음"

print(format_phone("010-1234-5678")) # 010-1234-5678
print(format_phone(None)) # 번호 없음

# 리스트/딕셔너리 컴프리헨션에서
users = [
{"name": "Alice", "score": 90},
{"name": "Bob", "score": 45},
{"name": "Charlie", "score": 72},
]

results = [
{"name": u["name"], "status": "합격" if u["score"] >= 60 else "불합격"}
for u in users
]
for r in results:
print(f"{r['name']}: {r['status']}")
# Alice: 합격
# Bob: 불합격
# Charlie: 합격

2. 삼항 연산자 중첩 주의사항

score = 75

# 나쁜 예 — 너무 많은 중첩으로 가독성 저하
grade = "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "D" if score >= 60 else "F"

# 이 경우 일반 if-elif가 훨씬 가독성이 좋음
def get_grade(score: int) -> str:
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"

# 또는 딕셔너리 매핑
def get_grade_v2(score: int) -> str:
thresholds = [(90, "A"), (80, "B"), (70, "C"), (60, "D")]
for threshold, grade in thresholds:
if score >= threshold:
return grade
return "F"

# 좋은 중첩 예 (두 단계까지는 허용)
x = 5
result = "양수" if x > 0 else ("음수" if x < 0 else "영")
print(result) # 양수

3. Walrus 연산자 (:=) — Python 3.8+ (PEP 572)

Walrus 연산자(:=)는 할당 표현식(Assignment Expression) 이라고도 합니다. 값을 변수에 할당하면서 동시에 그 값을 표현식으로 사용합니다.

이름의 유래: := 기호가 바다코끼리(Walrus)의 눈과 엄니를 닮았다고 해서 붙여진 별명입니다.

# 기본 사용법
# 일반 할당: result = some_function() (문장, statement)
# Walrus: result := some_function() (표현식, expression)

# 기존 방식
n = len([1, 2, 3, 4, 5])
if n > 3:
print(f"리스트 길이 {n}은 3보다 큽니다.")

# Walrus 연산자 사용
data = [1, 2, 3, 4, 5]
if (n := len(data)) > 3:
print(f"리스트 길이 {n}은 3보다 큽니다.")
# n을 한 번만 계산하면서 if 조건에도 사용

4. Walrus 연산자 주요 활용 패턴

while 루프 단순화

# 기존 방식 — 파일 읽기
with open("data.txt", "r", encoding="utf-8") as f:
while True:
chunk = f.read(1024)
if not chunk:
break
process_data(chunk)

# Walrus 연산자로 간결하게
with open("data.txt", "r", encoding="utf-8") as f:
while chunk := f.read(1024):
process_data(chunk)

# 사용자 입력 처리
# 기존 방식
while True:
user_input = input("명령 입력 (quit로 종료): ")
if user_input.lower() == "quit":
break
print(f"실행: {user_input}")

# Walrus 연산자
while (user_input := input("명령 입력 (quit로 종료): ")).lower() != "quit":
print(f"실행: {user_input}")

리스트 컴프리헨션에서 중간 계산값 재사용

# 기존 방식 — 같은 계산을 두 번 (비효율)
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = [expensive(x) for x in data if expensive(x) > 5]

# Walrus 연산자 — 한 번만 계산
def expensive(x: int) -> int:
"""비용이 큰 연산 시뮬레이션"""
return x * x + x // 2

result = [y for x in data if (y := expensive(x)) > 5]
print(result) # expensive()가 한 번씩만 호출됨

# 실전 예: 필터링 후 변환
numbers = range(-5, 6)
positive_roots = [root for x in numbers if (root := x ** 0.5) > 0 and x > 0]
print(positive_roots) # [1.0, 1.4142..., 1.7320..., 2.0, 2.2360...]

중첩 표현식 단순화

# 딕셔너리 키 존재 확인 후 처리
config = {"database": {"host": "localhost", "port": 5432}}

# 기존 방식
db_config = config.get("database")
if db_config:
host = db_config.get("host")
if host:
print(f"DB 호스트: {host}")

# Walrus 연산자
if (db := config.get("database")) and (host := db.get("host")):
print(f"DB 호스트: {host}")

5. 표현식(Expression) vs 문장(Statement) 차이

# 표현식(Expression): 값을 생성하는 코드
# → 변수에 할당하거나 함수 인수로 전달 가능

x = 5 + 3 # 5 + 3은 표현식 → 8
result = max(1, 2) # max(1, 2)는 표현식 → 2
flag = x > 0 # x > 0은 표현식 → True

# 문장(Statement): 실행되지만 값을 만들지 않는 코드
# → 변수에 할당하거나 함수 인수로 전달 불가

x = 10 # 할당문 (statement)
if x > 0: # if문 (statement)
pass
for i in range(5): # for문 (statement)
pass

# Walrus 연산자: 할당을 표현식으로 만들어 줌
# 일반 할당(=)은 문장이지만, Walrus(:=)는 표현식

# 이것은 문법 오류 (= 는 문장)
# if x = len(data): ...

# 이것은 가능 (:= 는 표현식)
data = [1, 2, 3]
if n := len(data):
print(f"데이터 {n}개")

6. 실전 예제

Walrus로 정규식 매칭 결과 처리

import re

texts = [
"전화번호: 010-1234-5678",
"이름: 홍길동",
"이메일: alice@example.com",
"연락처: 02-999-0000",
"주소: 서울시 강남구",
]

phone_pattern = re.compile(r"\d{2,3}-\d{3,4}-\d{4}")

# 기존 방식
for text in texts:
match = phone_pattern.search(text)
if match:
print(f"전화번호 발견: {match.group()}")

# Walrus 연산자로 간결하게
for text in texts:
if match := phone_pattern.search(text):
print(f"전화번호 발견: {match.group()}")

# 출력:
# 전화번호 발견: 010-1234-5678
# 전화번호 발견: 02-999-0000

파일 청크 읽기 (실전 패턴)

def process_large_file(filename: str, chunk_size: int = 8192) -> int:
"""대용량 파일을 청크 단위로 처리합니다."""
total_bytes = 0

with open(filename, "rb") as f:
while data := f.read(chunk_size):
# 데이터 처리
total_bytes += len(data)

return total_bytes

# 텍스트 줄 단위 처리
def process_lines(filename: str) -> list[str]:
"""파일에서 비어있지 않은 줄만 처리합니다."""
results = []
with open(filename, "r", encoding="utf-8") as f:
while line := f.readline():
if stripped := line.strip(): # 공백 제거 후 빈 줄 건너뜀
results.append(stripped.upper())
return results

고수 팁: Walrus 남용 금지 — 가독성이 먼저

Walrus 연산자는 강력하지만 과도하게 사용하면 오히려 코드를 이해하기 어렵게 만듭니다.

# 나쁜 예 — Walrus 남용으로 가독성 저하
# 이 코드가 무엇을 하는지 한눈에 이해하기 어렵습니다
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = [(y, z) for x in data if (y := x * 2) > 5 if (z := y + 1) < 15]
print(result)

# 좋은 예 — 명확한 단계별 처리
result = []
for x in data:
y = x * 2
if y > 5:
z = y + 1
if z < 15:
result.append((y, z))
print(result)

# 또 다른 좋은 예 — 적절한 Walrus 활용
def validate_and_process(items: list[str]) -> list[str]:
"""
항목을 검증하고 처리합니다.
Walrus를 적절하게 활용한 예시입니다.
"""
return [
cleaned
for item in items
if (cleaned := item.strip()) and len(cleaned) > 2
]

items = [" hello ", " hi ", " ", "world", "ok"]
print(validate_and_process(items)) # ['hello', 'world']

# 판단 기준:
# Walrus 쓰기 좋은 경우: 같은 계산 반복 방지, while 루프 단순화
# 일반 if문이 나은 경우: 중첩이 깊어질 때, 표현식이 복잡할 때

표현식 vs 문장 선택 기준:

# 간단하고 명확한 경우 → 조건 표현식 OK
status = "active" if user.is_active else "inactive"

# 복잡한 로직 → if문 사용
if user.is_active and user.email_verified and not user.is_banned:
send_newsletter(user)
elif user.is_active and not user.email_verified:
send_verification_email(user)
else:
log_inactive_user(user)

Ch 3에서는 파이썬의 다양한 연산자와 표현식을 살펴보았습니다. 산술·비교·논리 연산자부터 비트 연산, 문자열 고급 활용, 그리고 조건 표현식과 Walrus 연산자까지 익혔습니다. 다음 챕터(Ch 4)에서는 조건문과 반복문을 통해 프로그램의 흐름을 제어하는 방법을 배웁니다.

Advertisement