match/casePython 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을 frequency 와 times 에 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 한다.
Luciano Ramalho, Fluent Python, 2nd Edition, O'Reilly Media, Inc., April 2022