본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 3장: 구조적 패턴 매칭 실전 활용
2026년 1월 20일·프로그래밍·

3장: 구조적 패턴 매칭 실전 활용

Python의 match/case 문을 실전에서 활용하는 방법을 다룹니다. 시퀀스, 매핑, 클래스 패턴부터 가드 조건, 중첩 패턴까지 실무 코드로 익힙니다.

14분920자12개 섹션
pythontypescriptperformancedevtoolsconcurrency
공유
python-trends3 / 13
12345678910111213
이전2장: 타입 파라미터 새 문법 - PEP 695다음4장: 유연한 f-string과 개선된 에러 메시지

패턴 매칭이 필요한 이유

Python 3.10에서 도입된 구조적 패턴 매칭(Structural Pattern Matching)은 단순한 switch-case가 아닙니다. 데이터의 구조를 검사하고, 동시에 내부 값을 추출하는 강력한 제어 흐름 도구입니다.

기존의 if-elif 체인은 조건이 복잡해질수록 가독성이 급격히 떨어집니다. 특히 JSON API 응답, 이벤트 처리, 명령어 파싱처럼 데이터의 형태에 따라 분기하는 코드에서 이 문제가 두드러집니다.

if-elif 체인의 한계
python
def handle_event(event: dict) -> str:
    if event.get("type") == "click" and "x" in event and "y" in event:
        x = event["x"]
        y = event["y"]
        return "Click at " + str(x) + ", " + str(y)
    elif event.get("type") == "keypress" and "key" in event:
        key = event["key"]
        if event.get("modifier"):
            return event["modifier"] + "+" + key
        return key
    elif event.get("type") == "scroll":
        return "Scroll " + str(event.get("direction", "down"))
    else:
        return "Unknown event"

패턴 매칭을 사용하면 동일한 로직을 더 명확하게 표현할 수 있습니다.

match/case 기본 문법

match 문은 주어진 값(subject)을 여러 패턴과 순서대로 비교합니다. 첫 번째로 매칭되는 패턴의 블록이 실행됩니다.

리터럴 패턴

가장 단순한 형태는 리터럴 값과의 비교입니다.

리터럴 패턴
python
def http_status(code: int) -> str:
    match code:
        case 200:
            return "OK"
        case 301:
            return "Moved Permanently"
        case 404:
            return "Not Found"
        case 500:
            return "Internal Server Error"
        case _:
            return "Unknown Status: " + str(code)

_는 와일드카드 패턴으로, 모든 값과 매칭됩니다. 다른 언어의 default와 같은 역할을 합니다.

OR 패턴

여러 패턴을 파이프(|)로 결합할 수 있습니다.

OR 패턴
python
def classify_status(code: int) -> str:
    match code:
        case 200 | 201 | 202 | 204:
            return "Success"
        case 301 | 302 | 307 | 308:
            return "Redirect"
        case 400 | 401 | 403 | 404:
            return "Client Error"
        case 500 | 502 | 503:
            return "Server Error"
        case _:
            return "Other"

시퀀스 패턴

리스트나 튜플의 구조를 매칭하고 내부 값을 동시에 추출할 수 있습니다. 이것이 패턴 매칭의 진정한 힘입니다.

시퀀스 패턴과 구조 분해
python
def parse_command(command: list[str]) -> str:
    match command:
        case ["quit"]:
            return "Exiting"
        case ["hello", name]:
            return "Hello, " + name
        case ["move", direction, distance]:
            return "Moving " + direction + " by " + distance
        case ["move", direction]:
            return "Moving " + direction + " by 1"
        case ["drop", *items]:
            return "Dropping: " + ", ".join(items)
        case []:
            return "Empty command"
        case _:
            return "Unknown command"
 
# 사용 예시
parse_command(["hello", "Alice"])     # "Hello, Alice"
parse_command(["move", "north"])      # "Moving north by 1"
parse_command(["drop", "a", "b"])     # "Dropping: a, b"

*items는 나머지 요소를 모두 캡처하는 확장 언패킹(extended unpacking)입니다. 가변 길이 시퀀스를 처리할 때 유용합니다.

매핑 패턴

딕셔너리의 구조를 매칭합니다. API 응답이나 설정 파일 처리에서 자주 사용됩니다.

매핑 패턴
python
def handle_api_response(response: dict) -> str:
    match response:
        case {"status": "success", "data": data}:
            return "Data received: " + str(len(data)) + " items"
        case {"status": "error", "message": msg, "code": code}:
            return "Error " + str(code) + ": " + msg
        case {"status": "error", "message": msg}:
            return "Error: " + msg
        case {"status": "pending", "retry_after": seconds}:
            return "Retry after " + str(seconds) + " seconds"
        case _:
            return "Unexpected response format"
Info

매핑 패턴은 부분 매칭(partial matching)을 수행합니다. 패턴에 명시한 키가 존재하면 매칭되며, 딕셔너리에 추가 키가 있어도 무시됩니다. 모든 키를 캡처하려면 **rest 구문을 사용합니다.

나머지 키 캡처
python
def process_config(config: dict) -> None:
    match config:
        case {"host": host, "port": int(port), **rest}:
            print("Server: " + host + ":" + str(port))
            if rest:
                print("Additional config: " + str(rest))

클래스 패턴

클래스 인스턴스의 속성을 기준으로 매칭할 수 있습니다. 도메인 모델이나 이벤트 처리에서 특히 유용합니다.

클래스 패턴
python
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: Circle | Rectangle) -> str:
    match shape:
        case Circle(center=Point(x=0, y=0), radius=r):
            return "Origin circle with radius " + str(r)
        case Circle(center=Point(x=x, y=y), radius=r) if r > 100:
            return "Large circle at (" + str(x) + ", " + str(y) + ")"
        case Circle(center=c, radius=r):
            return "Circle at " + str(c) + " with radius " + str(r)
        case Rectangle(width=w, height=h) if w == h:
            return "Square with side " + str(w)
        case Rectangle(top_left=Point(x=x, y=y), width=w, height=h):
            return "Rectangle at (" + str(x) + ", " + str(y) + ") size " + str(w) + "x" + str(h)

match_args 활용

dataclass는 자동으로 __match_args__를 설정하므로 위치 기반 매칭이 가능합니다. 일반 클래스에서도 이 속성을 정의할 수 있습니다.

__match_args__ 커스텀 정의
python
class Command:
    __match_args__ = ("action", "target")
 
    def __init__(self, action: str, target: str) -> None:
        self.action = action
        self.target = target
 
def execute(cmd: Command) -> str:
    match cmd:
        case Command("create", target):
            return "Creating " + target
        case Command("delete", target):
            return "Deleting " + target
        case Command("update", target):
            return "Updating " + target

가드 조건

if 절을 추가하여 패턴 매칭에 조건을 부여할 수 있습니다. 패턴이 구조적으로 매칭된 후에 가드 조건이 평가됩니다.

가드 조건 활용
python
def classify_age(person: dict) -> str:
    match person:
        case {"name": name, "age": age} if age < 0:
            return name + ": invalid age"
        case {"name": name, "age": age} if age < 13:
            return name + ": child"
        case {"name": name, "age": age} if age < 20:
            return name + ": teenager"
        case {"name": name, "age": age} if age < 65:
            return name + ": adult"
        case {"name": name, "age": age}:
            return name + ": senior"
        case _:
            return "Unknown person"

실전 활용: 이벤트 처리 시스템

실무에서 패턴 매칭이 가장 빛나는 영역은 이벤트 처리입니다. 다양한 형태의 이벤트를 타입에 따라 분기하고, 필요한 데이터를 추출하는 과정이 자연스럽습니다.

이벤트 처리 시스템
python
from dataclasses import dataclass, field
from datetime import datetime
 
@dataclass
class UIEvent:
    timestamp: datetime = field(default_factory=datetime.now)
 
@dataclass
class Click(UIEvent):
    x: int = 0
    y: int = 0
    button: str = "left"
 
@dataclass
class KeyPress(UIEvent):
    key: str = ""
    modifiers: list[str] = field(default_factory=list)
 
@dataclass
class Scroll(UIEvent):
    dx: int = 0
    dy: int = 0
 
@dataclass
class Resize(UIEvent):
    width: int = 0
    height: int = 0
 
def handle_ui_event(event: UIEvent) -> str:
    match event:
        case Click(x=x, y=y, button="right"):
            return "Context menu at " + str(x) + ", " + str(y)
        case Click(x=x, y=y, button="left"):
            return "Click at " + str(x) + ", " + str(y)
        case KeyPress(key="c", modifiers=["ctrl"]):
            return "Copy"
        case KeyPress(key="v", modifiers=["ctrl"]):
            return "Paste"
        case KeyPress(key=k, modifiers=[]):
            return "Key: " + k
        case KeyPress(key=k, modifiers=mods):
            return "+".join(mods) + "+" + k
        case Scroll(dy=dy) if dy > 0:
            return "Scroll up"
        case Scroll(dy=dy) if dy < 0:
            return "Scroll down"
        case Resize(width=w, height=h):
            return "Resize to " + str(w) + "x" + str(h)
        case _:
            return "Unhandled event"

실전 활용: JSON API 라우터

REST API의 요청을 패턴 매칭으로 라우팅하는 예시입니다.

API 라우터
python
def route_request(method: str, path: list[str], body: dict | None = None) -> dict:
    match (method, path):
        case ("GET", ["users"]):
            return {"action": "list_users"}
        case ("GET", ["users", user_id]):
            return {"action": "get_user", "id": user_id}
        case ("POST", ["users"]) if body:
            return {"action": "create_user", "data": body}
        case ("PUT", ["users", user_id]) if body:
            return {"action": "update_user", "id": user_id, "data": body}
        case ("DELETE", ["users", user_id]):
            return {"action": "delete_user", "id": user_id}
        case ("GET", ["users", user_id, "posts"]):
            return {"action": "list_user_posts", "user_id": user_id}
        case _:
            return {"action": "not_found", "method": method, "path": "/".join(path)}

튜플 매칭을 활용하면 HTTP 메서드와 경로를 동시에 검사할 수 있습니다.

패턴 매칭과 타입 가드

Python 3.12의 타입 파라미터 문법과 함께 사용하면, 타입 안전한 패턴 매칭 코드를 작성할 수 있습니다.

타입 가드와 패턴 매칭
python
from dataclasses import dataclass
 
@dataclass
class Success[T]:
    value: T
 
@dataclass
class Failure:
    error: str
    code: int = 0
 
type Result[T] = Success[T] | Failure
 
def process_result[T](result: Result[T]) -> str:
    match result:
        case Success(value=v):
            return "Success: " + str(v)
        case Failure(error=e, code=0):
            return "Error: " + e
        case Failure(error=e, code=c):
            return "Error " + str(c) + ": " + e

주의사항과 모범 사례

순서에 주의

패턴은 위에서 아래로 순서대로 평가됩니다. 더 구체적인 패턴을 먼저 배치해야 합니다.

패턴 순서의 중요성
python
# 잘못된 순서: 첫 번째 case가 모든 것을 매칭
match point:
    case Point(x=x, y=y):      # 항상 매칭됨
        ...
    case Point(x=0, y=0):      # 도달 불가
        ...
 
# 올바른 순서: 구체적인 패턴을 먼저
match point:
    case Point(x=0, y=0):      # 원점만 매칭
        ...
    case Point(x=x, y=y):      # 나머지 모든 Point
        ...

성능 고려

패턴 매칭은 if-elif 체인과 비슷한 성능을 보입니다. 내부적으로 최적화된 점프 테이블을 사용하지 않으므로, 수백 개의 case를 나열하는 것은 권장하지 않습니다. 그러한 경우에는 딕셔너리 기반 디스패치가 더 적합합니다.

언제 사용할 것인가

Tip

패턴 매칭은 데이터의 구조를 검사하고 분해해야 할 때 가장 효과적입니다. 단순한 값 비교에는 if-elif가 더 명확할 수 있습니다. 중첩된 데이터 구조, 다형적 타입 처리, 이벤트 디스패치에서 패턴 매칭의 진가가 드러납니다.

정리

구조적 패턴 매칭은 Python에서 복잡한 조건 분기를 선언적으로 표현하는 도구입니다.

  • 리터럴, 시퀀스, 매핑, 클래스 등 다양한 패턴 유형을 지원합니다
  • 패턴 매칭과 동시에 값을 추출(구조 분해)할 수 있습니다
  • 가드 조건으로 매칭 후 추가 검증이 가능합니다
  • __match_args__를 통해 커스텀 클래스도 위치 기반 매칭을 지원합니다
  • 이벤트 처리, API 라우팅, 데이터 파싱에서 특히 유용합니다

다음 장 미리보기

4장에서는 Python 3.12의 유연한 f-string 파싱(PEP 701)과 3.12~3.13에 걸쳐 지속적으로 개선된 에러 메시지를 다룹니다. 디버깅 경험을 크게 향상시키는 이 변화들의 실체를 살펴봅니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#python#typescript#performance#devtools#concurrency

관련 글

프로그래밍

4장: 유연한 f-string과 개선된 에러 메시지

Python 3.12의 PEP 701 유연한 f-string 파싱과 3.12~3.13의 에러 메시지 개선을 다룹니다. 컬러 트레이스백, 제안 기반 에러 등 디버깅 경험 향상을 살펴봅니다.

2026년 1월 22일·13분
프로그래밍

2장: 타입 파라미터 새 문법 - PEP 695

Python 3.12에서 도입된 PEP 695 타입 파라미터 문법을 상세히 분석합니다. TypeVar의 간결한 선언, 제네릭 클래스와 함수의 새 문법, type 별칭을 다룹니다.

2026년 1월 18일·13분
프로그래밍

5장: PyREPL - 새로운 대화형 인터프리터

Python 3.13에서 도입된 PyREPL의 구문 강조, 멀티라인 편집, 자동완성, 히스토리 관리 등 현대적 REPL 기능을 실전 예시와 함께 다룹니다.

2026년 1월 24일·15분
이전 글2장: 타입 파라미터 새 문법 - PEP 695
다음 글4장: 유연한 f-string과 개선된 에러 메시지

댓글

목차

약 14분 남음
  • 패턴 매칭이 필요한 이유
  • match/case 기본 문법
    • 리터럴 패턴
    • OR 패턴
  • 시퀀스 패턴
  • 매핑 패턴
  • 클래스 패턴
    • undefinedmatch_args 활용
  • 가드 조건
  • 실전 활용: 이벤트 처리 시스템
  • 실전 활용: JSON API 라우터
  • 패턴 매칭과 타입 가드
  • 주의사항과 모범 사례
    • 순서에 주의
    • 성능 고려
    • 언제 사용할 것인가
  • 정리
  • 다음 장 미리보기