Практическое применение условной конструкции match case в Python
В Python есть несколько возможностей реализации условных конструкций. В данной статье будет рассмотрена конструкция match case, которая может быть полезна для сопоставления получаемого значения с образцами как альтернатива классическому if else.
Базовый пример использования с простыми типами
После оператора match указывается объект для сопоставления. Затем после оператора case перечисляются возможные образцы. В случае успешного сопоставления значения с образцом выполняется вложенный блок кода, при этом сопоставление с остальными образцами не производится. Специальный символ _ может использоваться для обработки любого значения, которое не соответствует перечисленным ранее образцам.
def http_status_code_message(code: int) -> str:
match int(str(code)[0]):
case 1:
return "1xx: Informational"
case 2:
return "2xx: Success"
case 3:
return "3xx: Redirection"
case 4:
return "4xx: Client Error"
case 5:
return "5xx: Server Error"
case _:
return "xxx: Invalid status code"
status_code_list = [
101,
201,
301,
401,
501,
601
]
for status_code in status_code_list:
print(http_status_code_message(status_code))
1xx: Informational
2xx: Success
3xx: Redirection
4xx: Client Error
5xx: Server Error
xxx: Invalid status code
Примеры использования с более сложными типами или классами
Помимо сопоставления всего передаваемого значения с образцом возможно выполнение более точечной проверки по конкретным элементам итерируемого объекта, произвольным атрибутам объекта класса и так далее.
Итерируемый объект
Специальный символ * может использоваться для распаковки элементов передаваемого итерируемого объекта.
from typing import List
def http_status_code_list_check(statuses: List[int]) -> str:
match statuses:
case [200, *_]:
return "It started pretty well"
case [*_, 200]:
return "All in all it ended well"
case []:
return "It didn't worked out at all"
case _:
return "We don't interested in such cases"
statuses_list = [
[],
[500],
[200, 301, 404],
[301, 404, 200]
]
for statuses in statuses_list:
print(f"{statuses}: {http_status_code_list_check(statuses)}")
[]: It didn't worked out at all
[500]: We don't interested in such cases
[200, 301, 404]: It started pretty well
[301, 404, 200]: All in all it ended well
Словарь
Специальный символ ** может использоваться для распаковки элементов передаваемого словаря. Однако его нельзя комбинировать со специальным символом _.
from typing import Dict
def http_status_code_dict_check(statuses: Dict[int, str]) -> str:
match statuses:
case {200: ok}:
return f"{ok} Only got 2xx"
case {**rest}:
return f"{rest} All we got"
statuses_dict = [
{200: "OK", 404: "Error"},
{301: "Moved Permanently", 404: "Error"},
]
for statuses in statuses_dict:
print(f"{statuses}: {http_status_code_dict_check(statuses)}")
{200: 'OK', 404: 'Error'}: OK Only got 2xx
{301: 'Moved Permanently', 404: 'Error'}: {301: 'Moved Permanently', 404: 'Error'} All we got
Объект класса
class StatusCode:
def __init__(self, code, message):
self.code = code
self.code_group = int(str(code)[0])
self.message = message
def __repr__(self):
return f"{self.code_group}xx: {self.message}"
def http_status_code_class_check(status: StatusCode) -> str:
match status.code_group:
case 1 | 2 | 3 | 4 | 5:
return f"Correct status code. {status}"
case _:
return "Incorrect status code. xxx: Invalid"
status_code_class_list = [
StatusCode(101, "Informational"),
StatusCode(201, "Success"),
StatusCode(301, "Redirection"),
StatusCode(401, "Client Error"),
StatusCode(501, "Server Error"),
StatusCode(601, "Unknown"),
]
for status_code_class in status_code_class_list:
print(http_status_code_class_check(status_code_class))
Correct status code. 1xx: Informational
Correct status code. 2xx: Success
Correct status code. 3xx: Redirection
Correct status code. 4xx: Client Error
Correct status code. 5xx: Server Error
Incorrect status code. xxx: Invalid
Пример использования в анализе данных
import pandas as pd
import sqlite3
df = pd.read_csv(
"https://raw.githubusercontent.com/" + \
"datasciencedojo/datasets/refs/heads/master/titanic.csv"
)
conn = sqlite3.connect("bdt.db")
query_ddl = """
create table if not exists titanic (
passenger_id integer,
survived integer,
p_class integer,
name text,
sex text,
age real,
sib_sp integer,
parch integer,
ticket text,
fare real,
cabin text,
embarked text
);
"""
conn.execute(query_ddl)
conn.commit()
df.to_sql(
name="titanic",
con=conn,
if_exists="replace",
index=False
)
cursor = conn.cursor()
cursor.execute("select * from titanic limit 5")
from typing import Tuple
def map_sex(data: Tuple) -> int:
match data[4]:
case "male":
return 0
case "female":
return 1
data = cursor.fetchone()
while data:
print(f"{data[4]}, {map_sex(data)}")
data = cursor.fetchone()
conn.close()
male, 0
female, 1
female, 1
female, 1
male, 0
Заключение
Таким образом, условная конструкция match case позволяет добавить в Python привычный для других языков механизм сопоставления значения с образцами. Для дальнейшего погружения рекомендуется ознакомиться с документацией.
Comments ()