match-case는 Python 3.10에서 도입된 구조적 패턴 매칭입니다. 이 치트시트는 리터럴, 시퀀스, 매핑, 클래스 패턴과 가드 조건 사용법을 정리합니다.
언제 이 치트시트를 보나?
- 복잡한 if-elif 체인을 더 읽기 쉽게 바꾸고 싶을 때
- 데이터 구조를 분해하면서 조건 분기할 때
핵심 패턴
match subject: + case pattern: 구문_ 와일드카드: 모든 값 매칭 (default)| OR 패턴: 여러 패턴 중 하나if 가드: 추가 조건 검사- 캡처: 패턴 내 변수에 값 바인딩
최소 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 기본 리터럴 매칭
def http_status(status: int) -> str:
match status:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Internal Server Error"
case _: # 와일드카드 (default)
return "Unknown"
print(http_status(200)) # OK
print(http_status(999)) # Unknown
|
1
2
3
4
5
6
7
8
9
10
11
| # OR 패턴 (|)
def categorize(code: int) -> str:
match code:
case 200 | 201 | 204:
return "Success"
case 400 | 401 | 403 | 404:
return "Client Error"
case 500 | 502 | 503:
return "Server Error"
case _:
return "Other"
|
시퀀스 패턴 (리스트/튜플)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| def process_command(command: list) -> str:
match command:
case ["quit"]:
return "Exiting..."
case ["hello", name]: # 캡처
return f"Hello, {name}!"
case ["add", x, y]:
return f"Result: {int(x) + int(y)}"
case ["echo", *args]: # *로 나머지 캡처
return " ".join(args)
case []:
return "Empty command"
case _:
return "Unknown command"
print(process_command(["hello", "Alice"])) # Hello, Alice!
print(process_command(["add", "2", "3"])) # Result: 5
print(process_command(["echo", "a", "b", "c"])) # a b c
|
매핑 패턴 (딕셔너리)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| def process_event(event: dict) -> str:
match event:
case {"type": "click", "x": x, "y": y}:
return f"Click at ({x}, {y})"
case {"type": "keypress", "key": key}:
return f"Key pressed: {key}"
case {"type": "scroll", "direction": d, **rest}: # 나머지 캡처
return f"Scroll {d}, extra: {rest}"
case {"type": t}:
return f"Unknown event type: {t}"
case _:
return "Invalid event"
print(process_event({"type": "click", "x": 100, "y": 200}))
# Click at (100, 200)
|
클래스 패턴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
@dataclass
class Circle:
center: Point
radius: float
@dataclass
class Rectangle:
top_left: Point
width: float
height: float
def describe_shape(shape) -> str:
match shape:
case Point(x=0, y=0):
return "Origin"
case Point(x=x, y=y):
return f"Point at ({x}, {y})"
case Circle(center=Point(x=x, y=y), radius=r):
return f"Circle at ({x}, {y}) with radius {r}"
case Rectangle(width=w, height=h) if w == h:
return f"Square with side {w}"
case Rectangle(width=w, height=h):
return f"Rectangle {w}x{h}"
case _:
return "Unknown shape"
print(describe_shape(Point(0, 0))) # Origin
print(describe_shape(Circle(Point(1, 2), 5))) # Circle at (1, 2) with radius 5
|
가드 조건 (if)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| def classify_number(n: int) -> str:
match n:
case 0:
return "Zero"
case x if x < 0:
return "Negative"
case x if x % 2 == 0:
return "Positive Even"
case _:
return "Positive Odd"
print(classify_number(-5)) # Negative
print(classify_number(4)) # Positive Even
print(classify_number(7)) # Positive Odd
|
Enum과 함께 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| from enum import Enum, auto
class State(Enum):
IDLE = auto()
RUNNING = auto()
PAUSED = auto()
STOPPED = auto()
def handle_state(state: State) -> str:
match state:
case State.IDLE:
return "Waiting for input..."
case State.RUNNING:
return "Processing..."
case State.PAUSED:
return "Paused, press resume"
case State.STOPPED:
return "Finished"
|
타입 체크 패턴
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| def process_value(value) -> str:
match value:
case bool(): # bool 먼저! (bool은 int의 서브클래스)
return f"Boolean: {value}"
case int():
return f"Integer: {value}"
case float():
return f"Float: {value}"
case str():
return f"String: {value}"
case list():
return f"List with {len(value)} items"
case dict():
return f"Dict with {len(value)} keys"
case _:
return f"Other: {type(value)}"
|
자주 하는 실수/주의점
- Python 3.10+ 필수: 이전 버전에서는 SyntaxError
- case 순서 중요: 위에서 아래로 순차 매칭, 먼저 매칭되면 종료
- bool vs int 순서:
bool은 int의 서브클래스이므로 bool() 패턴을 먼저 배치 - 변수 캡처 vs 상수:
1
2
3
4
5
6
7
8
9
| # 변수 캡처 (항상 매칭됨)
case x: # x에 값 바인딩
# 상수 비교 (리터럴만)
case 42: # 42와 같을 때만
# 상수를 변수로 비교하려면 가드 사용
MY_CONST = 42
case x if x == MY_CONST:
|
_ 와일드카드: 값이 바인딩되지 않음 (참조 불가)- 매핑 패턴: 지정하지 않은 키가 있어도 매칭됨 (부분 매칭)
if-elif vs match-case
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| # Before (if-elif)
def categorize_old(value):
if isinstance(value, bool):
return "bool"
elif isinstance(value, int) and value > 0:
return "positive int"
elif isinstance(value, int):
return "non-positive int"
elif isinstance(value, str):
return "string"
else:
return "other"
# After (match-case) - 더 선언적
def categorize_new(value):
match value:
case bool():
return "bool"
case int() as n if n > 0:
return "positive int"
case int():
return "non-positive int"
case str():
return "string"
case _:
return "other"
|
관련 링크(공식 문서)