Created
April 24, 2025
Created by
D
DaEun KimTags
Python
Property
참고하기 좋은 레퍼런스
기본적인 용법은 아래와 같다
(맨 위에 있는 케이스부터 차례대로 검사한다)
def match_tuple(t: tuple, flag: bool = False):
match t:
case ("JADU", 1):
print("case 1")
case ("JADU", 2) if flag:
print("case 2 with flag=true")
case ("JADU", 2):
print("case 2 without flag")
case ("JADU", n):
print(f"case 3 with {n=}")
case _:
print("nothing matched")
match_tuple(("JADU", 1)) # case 1
match_tuple(("JADU", 2)) # case 2 without flag
match_tuple(("JADU", 2), True) # case 2 with flag=true
match_tuple(("JADU", 100)) # case 3 with n=100
match_tuple(("DAEUN", 2)) # nothing matched
케이스 구문에는 단순한 리터럴 비교 뿐만 아니라 다양한 패턴을 작성할 수 있다
- 매칭의 대상에 변수 바인딩 가능
- 매칭의 대상이 시퀸스 객체일 경우
*
(positional argument) 으로 시퀸스 내 각 요소 접근 가능 - 매칭의 대상이 딕셔너리 객체일 경우
**
(keyword argument) 으로 각 key/value 접근 가능 - 매칭의 대상이 사용자가 정의한 클래스 객체일 경우 클래스 syntax 사용 가능
|
(vertical bar) 으로 2개 이상의 OR 조건 생성 가능as
으로 서브 패턴 접근 가능if
구문으로 guard (조건문 추가) 가능
상속 관계에 있는 클래스 객체를 비교하는 경우
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
@dataclass
class Shape:
center: Point
@dataclass
class Circle(Shape):
radius: float
@dataclass
class Rectangle(Shape):
width: float
height: float
@dataclass
class Line:
center: Point
def match_shape(shape: Shape):
match shape:
case Shape(center=Point(0.0, 0.0)):
print("shape with zero point")
case Circle(center=Point(x=x, y=y), radius=r):
print(f"circle with {x=}, {y=}, {r=}")
case Rectangle(center=Point(x=x, y=y), width=w, height=h):
print(f"rectangle with {x=}, {y=}, {w=}, {h=}")
case _:
print("nothing matched")
match_shape(Circle(center=Point(0.0,0.0), radius=20.0)) # shape with zero point
match_shape(Rectangle(center=Point(0.0,0.0), width=10.0, height=10.0)) # shape with zero point
match_shape(Circle(center=Point(1.0, 1.0), radius=35.0)) # circle with x=1.0, y=1.0, r=35.0
match_shape(Rectangle(center=Point(1.0 ,1.0), width=35.0, height=35.0)) # rectangle with x=1.0, y=1.0, w=35.0, h=35.0
match_shape(Line(center=Point(0.0, 0.0))) # nothing matched
if-elif-else
으로 작성한다면 대략 아래와 같이 작성해야 할텐데,
match
를 사용하니 훨씬 간결하고 명확해진다
def match_shape(shape: Shape):
if isinstance(shape, Shape):
if shape.center.x == 0.0 and shape.center.y == 0.0:
print("shape with zero point")
return
if isinstance(shape, Circle):
print(f"circle with x={shape.x}, y={shape.y}, r={shape.radius}")
else:
print(f"rectangle with x={shape.x}, y={shape.y}, width={shape.width}, height={shape.height}")}
else:
print("nothing matched")
케이스 구문에서 패턴 매칭하느라 분해된 개별 요소는 as
를 통해 원본으로 접근할 수 있다
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
@dataclass
class Shape:
name: str
center: Point
@dataclass
class Circle(Shape):
radius: float
@dataclass
class Rectangle(Shape):
width: float
height: float
def match_shape(shape: Shape):
match shape:
case Shape(center=Point(0, 0)) as shape:
print(f"{shape.__class__.__name__} with zero point")
case Circle(center=Point(x=x, y=y) as center) as circle:
print(f"circle with {center=}, name={circle.name}")
case Rectangle(center=Point(x=x, y=y) as center) as rectangle:
print(f"rectangle with {center=}, name={rectangle.name}")
case _:
print("nothing matched")
match_shape(Circle(center=Point(0.0,0.0), radius=20.0, name="c1")) # Circle with zero point
match_shape(Rectangle(center=Point(0.0,0.0), width=10.0, height=10.0, name="r1")) # Rectangle with zero point
match_shape(Circle(center=Point(1.0, 1.0), radius=35.0, name="c2")) # circle with center=Point(x=1.0, y=1.0), name=c2
match_shape(Rectangle(center=Point(1.0 ,1.0), width=35.0, height=35.0, name="r2")) # rectangle with center=Point(x=1.0, y=1.0), name=r2
각 케이스 블록에서 1개 이상의 조건을 만들기 위해 아래와 같이 vertical bar 활용하는 경우
from http import HTTPStatus
def classify_http_status(status):
match status:
case HTTPStatus.OK | HTTPStatus.CREATED | HTTPStatus.NO_CONTENT:
return "성공 응답"
case HTTPStatus.MOVED_PERMANENTLY | HTTPStatus.FOUND | HTTPStatus.TEMPORARY_REDIRECT | HTTPStatus.PERMANENT_REDIRECT:
return "리다이렉션 응답"
case HTTPStatus.BAD_REQUEST | HTTPStatus.UNAUTHORIZED | HTTPStatus.FORBIDDEN | HTTPStatus.NOT_FOUND:
return "클라이언트 오류 응답"
case HTTPStatus.INTERNAL_SERVER_ERROR | HTTPStatus.BAD_GATEWAY | HTTPStatus.SERVICE_UNAVAILABLE | HTTPStatus.GATEWAY_TIMEOUT:
return "서버 오류 응답"
case n if 100 <= n < 600:
return "기타 HTTP 상태 코드"
case _:
return "잘못된 HTTP 상태 코드"
classify_http_status(200) # 성공 응답
classify_http_status(401) # 클라이언트 오류 응답
classify_http_status(503) # 서버 오류 응답
classify_http_status(512) # 기타 HTTP 상태 코드
classify_http_status(777) # 잘못된 HTTP 상태 코드
if-elif-else
으로 구현할 경우 다소 복잡해지는 코드를 match-case
으로 더 간결하게 작성 가능함
def match_cmd(cmd: str):
match cmd.split():
case ["exit" | "bye" | "quit"]:
print("program terminated")
case ["open" | "load", file]:
print(f"{file} opened")
case ["search" | "find", *terms] if len(terms) > 0:
print(f"search '{" ".join(terms)}'")
case _:
print("unknown command")
match_cmd("quit") # program terminated
match_cmd("exit") # program terminated
match_cmd("open aaa") # aaa opened
match_cmd("load bbb") # bbb opened
match_cmd("search cat") # search 'cat'
match_cmd("search OIIA cat") # search 'OIIA cat'
match_cmd("hello") # unknown command