Structural Pattern Matching#
Python 3.10부터 도입된 구조적 패턴 매칭(Structural Pattern Matching) 은 데이터의 구조와 값을 기반으로 코드의 흐름을 제어하는 강력한 기능이다.
이는 기존의 if-elif-else
문을 대체하거나 보완하여 코드의 가독성과 유지보수성을 향상시키는 데 유용하다.
기본 개념 및 문법#
구조적 패턴 매칭은 match
문과 case
절을 사용하여 구현된다.
match
문은 주어진 표현식을 평가하고, 각 case
절은 해당 표현식의 결과와 비교할 패턴을 정의한다.
가장 먼저 일치하는 패턴의 코드 블록이 실행된다.
1
2
3
4
5
6
7
| match 표현식:
case 패턴1:
# 패턴1과 일치할 때 실행할 코드
case 패턴2:
# 패턴2와 일치할 때 실행할 코드
case _:
# 어떤 패턴과도 일치하지 않을 때 실행할 코드
|
여기서 case _:
는 와일드카드 패턴으로, 앞의 어떤 패턴과도 일치하지 않을 때 실행된다.
간단한 예제:
1
2
3
4
5
6
7
8
9
10
11
12
| def check_status(status):
match status:
case "online":
print("사용자가 온라인 상태입니다.")
case "offline":
print("사용자가 오프라인 상태입니다.")
case "away":
print("사용자가 자리를 비웠습니다.")
case _:
print("알 수 없는 상태입니다.")
check_status("online") # 출력: 사용자가 온라인 상태입니다.
|
- 다양한 패턴 매칭: 단순한 값 비교부터 복잡한 데이터 구조까지 매칭 가능.
- 구조 분해: 객체나 데이터 구조를 분해하여 내부 값을 추출할 수 있음.
- 가드 조건:
case
문에 if
조건을 추가하여 더 복잡한 매칭 로직 구현 가능. - OR 패턴:
|
연산자를 사용하여 여러 패턴을 하나의 case에서 처리 가능. - 타입 매칭: 객체의 타입을 기반으로 매칭 가능.
활용 예시#
OR 연산자를 사용한 다중 패턴 매칭: 여러 패턴 중 하나와 일치하면 코드를 실행한다.
1
2
3
4
5
6
7
8
9
10
| def access(user):
match user:
case "admin" | "manager":
return "전체 접근 권한"
case "guest":
return "제한된 접근 권한"
case _:
return "접근 권한 없음"
print(access("manager")) # 출력: 전체 접근 권한
|
조건부 매칭 사용:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| def categorize_score(score):
match score:
case score if score >= 90:
return "A"
case score if score >= 80:
return "B"
case score if score >= 70:
return "C"
case score if score >= 60:
return "D"
case _:
return "F"
print(categorize_score(85)) # 출력: B
|
기본 값 매칭#
1
2
3
4
5
6
7
8
| def process_command(command):
match command:
case "start":
return "시작합니다."
case "stop":
return "중지합니다."
case _:
return "알 수 없는 명령입니다."
|
구조 분해와 타입 매칭#
1
2
3
4
5
6
7
8
9
10
| def process_data(data):
match data:
case (x, y):
return f"좌표: ({x}, {y})"
case [str(name), int(age)]:
return f"이름: {name}, 나이: {age}"
case {"name": str(name), "age": int(age)}:
return f"이름: {name}, 나이: {age}"
case _:
return "알 수 없는 데이터 형식"
|
시퀀스 패턴 매칭:
1
2
3
4
5
6
7
8
9
10
| def process_coordinates(points):
match points:
case []:
print("빈 좌표 리스트")
case [x, y]:
print(f"2차원 좌표: ({x}, {y})")
case [x, y, z]:
print(f"3차원 좌표: ({x}, {y}, {z})")
case [x, y, *rest]:
print(f"2차원 이상의 좌표: 처음 두 값은 ({x}, {y}), 나머지: {rest}")
|
클래스 패턴 매칭:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| class User:
def __init__(self, username, role, active=True):
self.username = username
self.role = role
self.active = active
def process_user(user):
match user:
case User(username=name, role="admin", active=True):
print(f"활성 관리자: {name}")
case User(username=name, role="user", active=True):
print(f"활성 사용자: {name}")
case User(username=name, active=False):
print(f"비활성 계정: {name}")
case _:
print("알 수 없는 사용자 유형")
|
복합 패턴의 예제:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| def analyze_data_structure(data):
match data:
# 리스트 내부의 딕셔너리 매칭
case [{"type": "point", "x": int(x), "y": int(y)} as point, *rest]:
print(f"첫 번째 요소는 점 좌표: {point}")
if rest:
print(f"나머지 요소들: {rest}")
# 중첩된 구조 매칭
case {"data": [first, *middle, last], "type": str(type_name)}:
print(f"타입: {type_name}")
print(f"첫 번째: {first}, 마지막: {last}")
print(f"중간 요소들: {middle}")
# OR 패턴과 가드 조건 결합
case str(value) | int(value) as v if v > 0:
print(f"양수 값: {value}")
case _:
print("매칭되는 패턴이 없습니다")
|
실제 사용 사례를 통한 구조적 패턴 매칭의 활용:
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
| def process_command(command):
match command.split():
# 파일 관련 명령어 처리
case ["file", "create", name]:
print(f"파일 생성: {name}")
case ["file", "delete", name]:
print(f"파일 삭제: {name}")
case ["file", "move", source, dest]:
print(f"{source}를 {dest}로 이동")
# 사용자 관련 명령어 처리
case ["user", "add", username, *roles]:
print(f"사용자 추가: {username}")
if roles:
print(f"할당된 역할: {roles}")
case ["user", "remove", username]:
print(f"사용자 제거: {username}")
# 기본 명령어 처리
case ["help"]:
print("사용 가능한 명령어 목록…")
case ["exit" | "quit"]:
print("프로그램 종료")
case _:
print("알 수 없는 명령어")
|
고급 패턴 매칭 기법:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| def analyze_complex_data(data):
match data:
# 딕셔너리 부분 매칭
case {"user": {"name": str(name), **rest}}:
print(f"사용자 이름: {name}")
print(f"추가 정보: {rest}")
# 중첩된 시퀀스 매칭
case [[x, y] as point, *rest]:
print(f"첫 번째 점: {point}")
for p in rest:
print(f"추가 점: {p}")
# 복합 조건 매칭
case {"type": type_name, "value": value} if type_name in ["int", "float"] and value > 0:
print(f"양수 {type_name}: {value}")
|
가드 조건 사용#
패턴 매칭에 추가적인 조건을 부여할 때 사용
1
2
3
4
5
6
| def categorize_number(num):
match num:
case n if n 0 and n % 2 == 0:
return "양의 짝수"
case n if n > 0:
return "양의 홀수"
|
활용 시 주의사항#
- Python 3.10 이상에서만 사용 가능: 구조적 패턴 매칭은 Python 3.10 버전부터 도입되었으므로, 해당 버전 이상에서만 사용할 수 있다.
- 가독성 고려: 복잡한 패턴 매칭은 코드의 가독성을 떨어뜨릴 수 있으므로, 적절하게 사용해야 한다.
- 패턴 매칭은 위에서 아래로 순차적으로 평가되며, 첫 번째 일치하는 패턴에서 실행이 멈춘다.
최적화된 사용을 위한 팁#
- 패턴의 순서가 중요하다. 더 구체적인 패턴을 먼저 배치한다.
- 가드 조건은 패턴 매칭이 성공한 후에만 평가된다.
- 변수 캡처와 리터럴 매칭을 적절히 조합하여 사용한다.
- as 키워드를 사용하여 매칭된 전체 값을 참조할 수 있다.
참고 및 출처#