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)에서는 조건문과 반복문을 통해 프로그램의 흐름을 제어하는 방법을 배웁니다.