Pattern Matching - match/case

JInwoo·2025년 2월 3일

match/case

Python 3.10 에 pattern matching을 위한 문법인 match/case 가 추가되었다. 다음은 해당 feature의 사용 예시이다.

def handle_command(self, message):
	match message:
    	case ["BEEPER", frequency, times]:    # 1
        	self.beep(times, frequency)
        case ["NECK", angle]:   # 2
        	self.rotate_neck(angle)
        case ["LED", ident, intensity]:   # 3
        	self.leds[indent].set_brightness(indent, intensity)
        ...
        case _:
        	raise InvalidCommnad(message)

1 번째 case는 message가 3 개의 item을 가진 sequence이고 첫 번째 item이 "BEEPER"인 경우 해당한다. 그리고 각각 2 번째, 3 번째 item을 frequencytimes 에 bounding 하였다. 해당 case와 일치하면 case 절 아래에 있는 문장이 실행된다. 2 번째 case는 message 가 "NECK"으로 시작하는 item을 가지고 총 2개의 item을 가진 sequence임을 의미한다. 맨 마지만 _ 는 else case에 해당한다. switch 에 익숙한 사람이라면 해당 코드를 이해하기 쉬울 것이다.

switch 에 비해 match 가 가진 장점은 바로 deconstructing이다. 다음은 deconstructing을 활용한 예시이다.

metro_areas = [
    ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
    ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
    ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
    ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
    ('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
]

def main():
    print(f'{"":15} | {"latitude":>9} | {"longitude":>9}')
    for record in metro_areas:
        match record:  # <1>
            case [name, _, _, (lat, lon)] if lon <= 0:  # <2>
                print(f'{name:15} | {lat:9.4f} | {lon:9.4f}')

record는 총 4개의 item을 가지고 있고 마지막 item은 nested items인 경우, nested items는 반드시 2 개인 경우 case에 해당하게 된다. case 절이 if keyword로 optional guard가 붙은 것을 확인 할 수 있다. 이 경우 lon 이 0보다 작거나 같은 경우에만 matching이 된다.

upacking과 달리 pattern은 sequence가 아닌 iterable은 deconstruct 할 수 없다.(like iterator ) 그리고 pattern은 as keyword를 사용하여 pattern의 일부를 bounding 할 수 있다.

case [name, _, _, (lat, lon) as coord]:

또한 pattern에 type information을 추가할 수 있다.

case [str(name), _, _, (float(lat), float(lon)]:

위 코드는 str , float 함수 호출 처럼 보이지만, type을 변경하지 않고 해당 value가 각 type에 해당하는지를 확인한다.

*_ 를 이용하면 아무 숫자의 items들과 matching 시킬 수 있다.

case [str(name), *_, (float(lat), float(lon)]:

만약 *_ 이 아닌 *extra 같이 특정 이름을 사용하게 되면, 중간 모든 items들을 extra 에 bounding 한다.

Reference

Luciano Ramalho, Fluent Python, 2nd Edition, O'Reilly Media, Inc., April 2022

profile
Jr. AI Engineer

0개의 댓글