[Python] match case 한 방 정리: 복잡한 조건문, 이제 패턴 매칭으로 깔끔하게!
오늘은 파이썬 3.10 버전부터 새롭게 도입되어 많은 개발자들의 사랑을 받고 있는 조건문 match ... case
에 대해 자세히 알아보려고 합니다. 기존의 if-elif-else
구문보다 특정 상황에서 훨씬 직관적이고 강력한 패턴 매칭 기능을 제공하는데요, 그 정확한 개념과 다채로운 활용법을 함께 배워볼까요?
1. match ... case
기본 구조: 무엇이 달라졌을까요?
match ... case
문은 주어진 subject
(매칭 대상이 되는 변수나 값)를 여러 case
패턴과 비교하여, 첫 번째로 일치하는 패턴의 코드 블록을 실행하는 방식입니다.
기본 구조:
match subject:
case <패턴_1>:
# 패턴_1에 일치할 때 실행될 코드
case <패턴_2>:
# 패턴_2에 일치할 때 실행될 코드
case <패턴_3> if <추가_조건>: # 가드(guard) 조건 추가 가능
# 패턴_3에 일치하고, 추가_조건도 참일 때 실행될 코드
case _: # 와일드카드 (어떤 패턴에도 해당하지 않을 경우)
# 기본적으로 실행될 코드 (if-else의 else와 유사)
여기서 가장 중요한 점은 각 case
다음에는 값 자체를 조건으로 사용하여 위에서부터 차례대로 매칭을 시도한다는 것입니다. 물론, 들여쓰기는 파이썬의 기본! 잊지 마세요.
예시: 간단한 메뉴 선택기
# 리터럴 매칭 예시
menu_choice = int(input('메뉴 번호를 입력하세요 (1: 커피, 2: 주스, 3: 차) > '))
match menu_choice:
case 1:
print('☕️ 따뜻한 커피를 준비해드릴게요.')
case 2:
print('🍹 시원한 주스를 준비해드릴게요.')
case 3:
print('🍵 향긋한 차를 준비해드릴게요.')
case _: # 와일드카드: 위의 1, 2, 3이 아닌 모든 경우
print('😅 죄송합니다. 1, 2, 3 중에서만 선택해주세요.')
print('=====================')
위 코드에서 menu_choice
의 값(리터럴)에 따라 해당하는 case
문의 print
함수가 실행됩니다. _
(언더바)는 와일드카드라고 불리며, 이전 case
들에서 매칭되지 않은 모든 경우를 포괄합니다. 마치 if-elif-else
문의 마지막 else
와 같은 역할을 하죠.
2. 다양한 패턴 활용법: match ... case
의 진가!
match ... case
는 단순한 값 비교를 넘어, 데이터의 구조를 파악하고 특정 요소를 추출하는 데 매우 유용합니다.
주요 패턴 종류:
- 리터럴 패턴: 숫자, 문자열 등 고정된 값과 매칭 (위 예시)
- 와일드카드 패턴 (
_
): 어떤 값이든 매칭 (위 예시) - 캡처 패턴: 변수 이름을 사용하여 값을 "캡처" (저장)
- 시퀀스 패턴: 리스트나 튜플의 구조와 매칭
- OR 패턴 (
|
): 여러 패턴 중 하나라도 만족하면 매칭 - 별표 패턴 (
*
): 시퀀스에서 나머지 요소들을 캡처
예시: 복합적인 데이터 처리
# 시퀀스, OR, 캡처 패턴 예시
test_cases = [
["LOGIN", "user123"],
["LOGOUT"],
["POST", "My new article title"],
["COMMENT", 101, "Great post!"],
["DELETE", 205],
["FETCH", "all", "users"],
"INVALID_COMMAND"
]
for command_data in test_cases:
match command_data:
case ["LOGIN", username]: # 시퀀스 패턴 + 캡처 패턴
print(f"사용자 '{username}' 로그인 시도")
case ["LOGOUT"]: # 시퀀스 패턴 (리터럴)
print("사용자 로그아웃")
case ["POST", title] | ["COMMENT", _, title]: # OR 패턴 + 캡처 (두 번째 요소 캡처)
print(f"콘텐츠 관련 작업: '{title}'")
case ["DELETE", item_id]: # 시퀀스 패턴 + 캡처 패턴
print(f"항목 ID {item_id} 삭제 요청")
case ["FETCH", "all", *details]: # 별표(*) 패턴: 나머지 요소를 리스트로 캡처
print(f"모든 항목 가져오기, 세부 정보: {details}")
case str() if command_data == "INVALID_COMMAND": # 타입 패턴 + 가드(guard)
print(f"문자열 명령 감지: {command_data}")
case _: # 와일드카드
print(f"알 수 없는 명령: {command_data}")
# 출력 결과:
# 사용자 'user123' 로그인 시도
# 사용자 로그아웃
# 콘텐츠 관련 작업: 'My new article title'
# 콘텐츠 관련 작업: 'Great post!'
# 항목 ID 205 삭제 요청
# 모든 항목 가져오기, 세부 정보: ['users']
# 문자열 명령 감지: INVALID_COMMAND
위 예시를 자세히 살펴볼까요?
case ["LOGIN", username]
:command_data
가 2개의 요소를 가진 리스트이고, 첫 번째 요소가 "LOGIN"이면 두 번째 요소를username
변수에 캡처합니다.case ["LOGOUT"]
: 정확히["LOGOUT"]
리스트와 일치할 때 실행됩니다.case ["POST", title] | ["COMMENT", _, title]
:command_data
가["POST", ...]
형태이거나["COMMENT", ..., ...]
형태일 때 매칭됩니다.|
(파이프)는 OR 조건을 의미합니다.["POST", title]
에서는 두 번째 요소가title
에 캡처됩니다.["COMMENT", _, title]
에서는 첫 번째 요소는 "COMMENT", 두 번째 요소는 와일드카드(_
)로 무시하고, 세 번째 요소가title
에 캡처됩니다.
case ["FETCH", "all", *details]
:- 첫 두 요소가 "FETCH", "all"과 일치하고, 그 뒤에 오는 모든 나머지 요소들을
details
라는 이름의 리스트로 캡처합니다. (*
는 '나머지 전부'를 의미)
- 첫 두 요소가 "FETCH", "all"과 일치하고, 그 뒤에 오는 모든 나머지 요소들을
case str() if command_data == "INVALID_COMMAND"
:str()
은command_data
가 문자열 타입인지 확인하는 타입 패턴입니다.if command_data == "INVALID_COMMAND"
는 가드(guard)라고 하며, 패턴 매칭 후 추가적인 조건을 검사합니다.
3. match ... case
언제 사용하면 좋을까요? 핵심 정리!
- 값 자체 또는 데이터 구조를 기반으로 분기할 때:
if-elif-else
보다 코드가 훨씬 명확하고 간결해질 수 있습니다. 특히 JSON 데이터나 API 응답처럼 구조화된 데이터를 다룰 때 유용합니다. - 여러 조건을 OR로 묶어 처리할 때:
|
패턴을 사용하면 여러case
를 하나로 합칠 수 있어 중복 코드를 줄입니다. - 시퀀스 내 일부 요소만 필요하거나, 나머지 요소를 한 번에 받고 싶을 때: 캡처 패턴과
*
패턴이 빛을 발합니다. - 와일드카드(
_
)로 기본 처리: 명시적으로 처리하지 않은 모든 경우에 대한 기본 동작을 쉽게 정의할 수 있습니다.
마무리 꿀팁!
- 단순 값 비교가 여러 개 필요한 경우,
match...case
를 고려해보세요. - 하나의
case
에서 여러 조건을 확인하고 싶다면|
(OR)를 적극 활용하세요. - 리스트나 튜플에서 특정 부분을 제외한 나머지를 깔끔하게 받고 싶다면
*변수명
을 사용하세요. case
문의 순서가 중요합니다! 위에서부터 순차적으로 매칭되므로, 더 구체적인 패턴을 위에, 일반적인 패턴(특히 와일드카드)을 아래에 두는 것이 좋습니다.
match ... case
문은 파이썬의 표현력을 한층 더 높여주는 강력한 도구입니다. 처음에는 조금 낯설 수 있지만, 익숙해지면 복잡한 조건 분기를 놀랍도록 깔끔하게 정리할 수 있게 될 거예요. 직접 다양한 예제를 만들어보면서 그 매력을 느껴보시길 바랍니다!