본문 바로가기
C.W.K.
Stream
Lesson 02 of 07 · published

match — 값이 아니라 구조로 나누기

~20 min · match, pattern-matching, switch, 3.10

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

Python 3.10의 구조 패턴 매칭

match는 다른 언어의 단순한 switch보다 넓어. 값뿐 아니라 시퀀스의 길이와 자리, 딕셔너리의 키, 객체의 필드를 한 번에 확인하고 필요한 부분을 이름에 담을 수 있어.

리터럴, 와일드카드, 캡처

숫자나 문자열 리터럴은 같은 값과 맞고, _는 나머지 모든 경우를 받아. 반면 case name:의 맨 이름은 상수 비교가 아니라 어떤 값이든 받아 name에 묶는 캡처야. 상수를 비교하려면 Status.ACTIVE처럼 점이 있는 이름을 써.

모양을 풀고 조건을 더한다

시퀀스 패턴은 위치를, 매핑 패턴은 필요한 키를, 클래스 패턴은 공개된 속성을 풀어 받아. if 가드는 모양이 맞은 뒤 추가 조건을 검사해. 모든 분기를 match로 바꾸지 말고, 한 데이터의 여러 구조를 분해할 때 써.

원칙: 분기의 기준이 “무슨 값인가”보다 “어떤 모양인가”에 가까울수록 match가 빛나.

Code

리터럴과 와일드카드 패턴·python
def describe(status):
    match status:
        case 200:
            return "OK"
        case 301 | 302:
            return "redirect"
        case 404:
            return "not found"
        case n if 500 <= n < 600:
            return "server error"
        case _:
            return "unknown"

print(describe(200))      # OK
print(describe(301))      # redirect
print(describe(503))      # server error
print(describe(700))      # unknown
시퀀스의 자리를 풀어 받기·python
def parse(command):
    match command.split():
        case ["quit"]:
            return "exit"
        case ["go", direction]:
            return f"moving {direction}"
        case ["go", direction, distance]:
            return f"moving {direction} by {distance}"
        case [action, *args]:
            return f"action={action}, args={args}"
        case []:
            return "empty command"

print(parse("quit"))               # exit
print(parse("go north"))           # moving north
print(parse("go north 5"))         # moving north by 5
print(parse("jump high quickly"))  # action=jump, args=['high', 'quickly']
print(parse(""))                   # empty command
JSON 모양의 매핑 패턴·python
def handle(event):
    match event:
        case {"type": "login", "user": user}:
            return f"login: {user}"
        case {"type": "logout", "user": user, "reason": reason}:
            return f"logout: {user} ({reason})"
        case {"type": "error", **rest}:
            return f"error event: {rest}"
        case _:
            return "unhandled"

print(handle({"type": "login", "user": "alice"}))
print(handle({"type": "logout", "user": "alice", "reason": "timeout"}))
print(handle({"type": "error", "code": 500, "msg": "oops"}))
객체의 필드를 푸는 클래스 패턴·python
from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float

@dataclass
class Circle:
    center: Point
    radius: float

def shape_summary(shape):
    match shape:
        case Point(0, 0):
            return "원점"
        case Point(x, 0):
            return f"x 축 위 {x}"
        case Point(x, y):
            return f"점 ({x}, {y})"
        case Circle(Point(0, 0), r):
            return f"원점 중심 원, r={r}"
        case Circle(_, r) if r > 100:
            return f"큰 원 r={r}"
        case _:
            return "unknown"

print(shape_summary(Point(0, 0)))
print(shape_summary(Point(3, 0)))
print(shape_summary(Circle(Point(0, 0), 5)))
캡처 이름과 상수 비교의 차이·python
ACTIVE = "active"
INACTIVE = "inactive"

def status_of(s):
    match s:
        case ACTIVE:           # 잘못됨 — 이건 CAPTURE, 뭐든 매치
            return "is active"
        case _:
            return "unknown"

print(status_of("foo"))   # 'is active'  <- 버그! 'foo' 가 ACTIVE 로 캡쳐됨

# 맞음 — dotted name (enum 또는 클래스 속성)
class Status:
    ACTIVE = "active"
    INACTIVE = "inactive"

def status_of_v2(s):
    match s:
        case Status.ACTIVE:    # 맞음 — 상수와 비교
            return "is active"
        case _:
            return "unknown"

print(status_of_v2("foo"))    # 'unknown'  ✓
print(status_of_v2("active")) # 'is active'  ✓

External links

Exercise

딕셔너리를 받는 process(message)를 만들고 match로 나눠. {'type': 'chat', 'text': ...}는 text를 대문자로, {'type': 'command', 'name': ..., 'args': [...]}는 명령 이름과 인자 수를, {'type': 'event', 'name': ..., **rest}는 이벤트 이름과 추가 필드 수를 돌려줘. 나머지는 'unknown'으로 처리하고 네 가지 이상을 시험해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.