match문
1. match문 사용하기
파이썬 3.10 버전부터 추가된 match
문법은 파이썬에 없는 switch
문을 사용하기 위해 등장했습니다. 사용자는 match
문법을 이용하여 여러 조건문처럼 여러 경우의 수를 처리할 수 있습니다.
1.1 match문이란?
match
문은 여러 조건을 체크하여 해당 조건에 맞는 코드 블록을 실행하는 제어문입니다. switch라는 이름으로 다양한 프로그래밍 언어에서 지원되며, 일반적으로 if-elif-else 문보다 가독성이 좋습니다.
파이썬은 switch
문법을 지원하지 않았습니다. 이로 인해 개발자들은 여러 가지 경우의 수를 처리하기 위해 if-else
문이나 dict
의 get
메소드를 사용했어야 했습니다. 파이썬에서는 switch
문을 if
문으로 표현할 수 있으며, 파이썬의 간결성을 해친다고 생각하였습니다. 이러한 논의는 파이썬 3.0부터 진행되어 왔습니다. 보다 자세한 논의는 아래 문서에서 확인할 수 있습니다.
오랫동안 이 논의가 활발히 진행되었고 match
문을 Python 3.10 이상에서 사용할 수 있게 되었습니다.
1.2 match 문법 활용 코드
- 첫 번째 경우: 'Hello' 문자열과 일치하는지 확인합니다. 일치하지 않으므로 이 경우는 건너뜁니다.
- 두 번째 경우: 'World' 문자열과 일치하는지 확인합니다. 일치하지 않으므로 이 경우도 건너뜁니다.
- 세 번째 경우:
_
는 와일드카드로, 어떤 값과도 일치한다는 것을 나타냅니다. 따라서 이 경우가 실행되며 ‘No Match’라는 문자열이 출력됩니다.
위 코드에서 case _
는 일종의 '디폴트 케이스'로 작동하며, 어떠한 값도 받아들일 수 있는 와일드카드 역할을 합니다. 이것은 if-elif-else
구조에서의 else
절과 비슷한 작용을 하는데, 어느 조건도 충족하지 않을 때 해당 코드 블록이 실행됩니다.
즉, 'World'라는 문자열은 앞선 두 케이스 조건, 'Hello'와 'World'에 부합하지 않기 때문에, case _:
에 지정된 코드 블록이 실행되어 'No Match'가 출력됩니다. match
문에 의해 이 문자열은 평가되며, 해당 조건에 맞는 케이스를 찾아 그에 따른 블록을 실행하게 됩니다.
아래 코드는 text가 ‘World’이기 때문에 case 'World'
조건 부합하여 print('World')
를 실행합니다.
다른 언어에서 일반적으로 사용되는 구분인 아래와 같은 코드는 Python에서는 작동하지 않습니다.
두 조건이 모두 print(’1, 2’)를 수행하길 원했다면 아래와 같은 코드로 작성해야 합니다. 여기서 |
대신 and
나 or
연산자는 가능하지 않습니다.
2. match 문법 다양한 예제
다음은 구조적 패턴 매칭을 사용하여 i
변수의 값을 여러 경우에 따라 검사하는 test
함수를 정의하고 있습니다. 여러 case
문을 사용하여 다양한 조건을 검사합니다. 아래 예제에서 case 3 | 4
구문은 case 3 or case 4
와 같습니다.
각 함수는 입력된 변수의 타입을 확인하고 해당 타입의 이름을 출력합니다. 두 코드 조각은 비슷하지만 변수 이름을 패턴으로 사용하는 것과 와일드카드 패턴을 사용하는 것에 차이가 있습니다. 아래 예제에서는 if문을 사용하여 type을 비교하여 다양한 값을 처리합니다. 아래 코드에서 if를 제거하는 것은 허용하지 않습니다.
해당 예제는 i
변수의 값을 여러 경우에 따라 검사하는 test
함수를 정의하고 있습니다. 여러 case
문을 사용하여 다양한 조건을 검사합니다. 다음과 같이 case block 내부에서도 if-else 문을 사용할 수 있습니다.
해당 예제에서는 status
라는 매개변수를 받아와 그 값이 1, 2, 3 중 하나인지 확인한 후, 해당 값이 맞다면 문자열에 그 값을 포함하여 반환하고, 그렇지 않다면 'hello'를 반환하는 함수를 정의하고 있습니다. as 키워드를 사용하여 변수명으로 사용할 수 있습니다.
해당 예제는 status
라는 매개변수의 값을 검사하고, 그 값이 1, 2, 3 중 하나이며 동시에 짝수인지 확인합니다. 해당 조건이 맞다면 'hello'를 반환하고, 그렇지 않다면 'world'를 반환하는 함수를 정의하고 있습니다.
3. 나아가기
match
문법은 if
문법이나 dict
의 get
메서드보다 가독성이 좋습니다. 성능은 if
와 비교하면 그 차이는 미미합니다. 아래 소스코드는 Best Case
와 Worst Case
를 비교한 결과입니다. 조건이 2개만 되어도 dict.get()
이 가장 빠릅니다. 나머지 2개만 비교했을 때에는 베스트일 경우에는 if
문이, 워스트일 경우에는 match
문이 빠릅니다. 실행은 colab 환경에서 진행하였습니다. 해당 실행 결과는 실행할 때마다, 환경에 따라 다를 수 있습니다. 여기서 중요한 포인트는 두 차이가 미미하다는 것과 조건이 2개만 되어도 get()
메서드가 가장 빠르다는 것입니다.
# match, if, dict.get문 성능 비교
테스트 키: key_0
If-Elif 방식 (10 조건): 0.159554 초
Match-Case 방식 (10 조건): 0.170885 초
Dict.get() 방식 (10 항목): 0.205562 초
테스트 키: key_9
If-Elif 방식 (10 조건): 0.496979 초
Match-Case 방식 (10 조건): 0.461650 초
Dict.get() 방식 (10 항목): 0.203502 초
# match, if, dict.get문 성능 비교
테스트 키: key_0
If-Elif 방식 (10 조건): 0.159554 초
Match-Case 방식 (10 조건): 0.170885 초
Dict.get() 방식 (10 항목): 0.205562 초
테스트 키: key_9
If-Elif 방식 (10 조건): 0.496979 초
Match-Case 방식 (10 조건): 0.461650 초
Dict.get() 방식 (10 항목): 0.203502 초
테스트 코드입니다.
import timeit
# 10개의 키-값 쌍 생성
data = {f"key_{i}": f"value_{i}" for i in range(10)}
# 테스트할 키
# Best
# test_key = 'key_0'
# Worst
test_key = 'key_9'
def using_if(key):
if key == "key_0":
return "value_0"
elif key == "key_1":
return "value_1"
elif key == "key_2":
return "value_2"
elif key == "key_3":
return "value_3"
elif key == "key_4":
return "value_4"
elif key == "key_5":
return "value_5"
elif key == "key_6":
return "value_6"
elif key == "key_7":
return "value_7"
elif key == "key_8":
return "value_8"
elif key == "key_9":
return "value_9"
else:
return "Not found"
def using_match(key):
match key:
case "key_0":
return "value_0"
case "key_1":
return "value_1"
case "key_2":
return "value_2"
case "key_3":
return "value_3"
case "key_4":
return "value_4"
case "key_5":
return "value_5"
case "key_6":
return "value_6"
case "key_7":
return "value_7"
case "key_8":
return "value_8"
case "key_9":
return "value_9"
case _:
return "Not found"
def using_dict_get(key):
return data.get(key, "Not found")
# 벤치마크 함수
def benchmark_if():
return using_if(test_key)
def benchmark_match():
return using_match(test_key)
def benchmark_dict_get():
return using_dict_get(test_key)
# 벤치마크 실행
number = 1000000
if_time = timeit.timeit(benchmark_if, number=number)
match_time = timeit.timeit(benchmark_match, number=number)
dict_get_time = timeit.timeit(benchmark_dict_get, number=number)
print(f"테스트 키: {test_key}")
print(f"If-Elif 방식 (10 조건): {if_time:.6f} 초")
print(f"Match-Case 방식 (10 조건): {match_time:.6f} 초")
print(f"Dict.get() 방식 (10 항목): {dict_get_time:.6f} 초")
# 결과 검증
print("\n결과 검증:")
print(f"If-Elif 결과: {using_if(test_key)}")
print(f"Match-Case 결과: {using_match(test_key)}")
print(f"Dict.get() 결과: {using_dict_get(test_key)}")
import timeit
# 10개의 키-값 쌍 생성
data = {f"key_{i}": f"value_{i}" for i in range(10)}
# 테스트할 키
# Best
# test_key = 'key_0'
# Worst
test_key = 'key_9'
def using_if(key):
if key == "key_0":
return "value_0"
elif key == "key_1":
return "value_1"
elif key == "key_2":
return "value_2"
elif key == "key_3":
return "value_3"
elif key == "key_4":
return "value_4"
elif key == "key_5":
return "value_5"
elif key == "key_6":
return "value_6"
elif key == "key_7":
return "value_7"
elif key == "key_8":
return "value_8"
elif key == "key_9":
return "value_9"
else:
return "Not found"
def using_match(key):
match key:
case "key_0":
return "value_0"
case "key_1":
return "value_1"
case "key_2":
return "value_2"
case "key_3":
return "value_3"
case "key_4":
return "value_4"
case "key_5":
return "value_5"
case "key_6":
return "value_6"
case "key_7":
return "value_7"
case "key_8":
return "value_8"
case "key_9":
return "value_9"
case _:
return "Not found"
def using_dict_get(key):
return data.get(key, "Not found")
# 벤치마크 함수
def benchmark_if():
return using_if(test_key)
def benchmark_match():
return using_match(test_key)
def benchmark_dict_get():
return using_dict_get(test_key)
# 벤치마크 실행
number = 1000000
if_time = timeit.timeit(benchmark_if, number=number)
match_time = timeit.timeit(benchmark_match, number=number)
dict_get_time = timeit.timeit(benchmark_dict_get, number=number)
print(f"테스트 키: {test_key}")
print(f"If-Elif 방식 (10 조건): {if_time:.6f} 초")
print(f"Match-Case 방식 (10 조건): {match_time:.6f} 초")
print(f"Dict.get() 방식 (10 항목): {dict_get_time:.6f} 초")
# 결과 검증
print("\n결과 검증:")
print(f"If-Elif 결과: {using_if(test_key)}")
print(f"Match-Case 결과: {using_match(test_key)}")
print(f"Dict.get() 결과: {using_dict_get(test_key)}")