![Конструкция match/case: примеры и фишки для студентов-программистов - 1]()
Привет, кодерам и будущим гуру Python! Сегодня разберем конструкцию
match/case, которая появилась в Python 3.10. Если вы до сих пор пишете бесконечные
if/elif/else, то пора прокачать свои скиллы и перейти на что-то более крутое и читаемое. Давайте разбираться, как это работает, на примерах, которые будут понятны даже тем, кто только начал изучать Python.
Подключение к базе данных: пример с match/case
Представьте, что вам нужно подключиться к базе данных. У вас есть словарь с данными для подключения:
request = {'server': '127.0.0.1', 'login': 'root', 'password': '1234', 'port': 24}
Ваша задача — написать функцию
connect_db(), которая проверит данные и вернет строку с результатом подключения. Вот как это можно сделать с помощью
match/case:
def connect_db(connect: dict) -> str:
match connect:
case {'server': host, 'login': login, 'password': psw, 'port': port}:
return f"connection: {host}@{login}.{psw}:{port}"
case {'server': host, 'login': login, 'password': psw}:
port = 22 # Если порт не указан, используем дефолтный
return f"connection: {host}@{login}.{psw}:{port}"
case _: # Если данные не подходят
return "error connection"
Здесь мы видим, что в первых двух
case есть дублирование кода — строка с возвратом результата. Чтобы не повторяться, можно вынести эту строку за пределы
match:
def connect_db(connect: dict) -> str:
match connect:
case {'server': host, 'login': login, 'password': psw, 'port': port}:
pass # Просто пропускаем, но переменные сохраняются
case {'server': host, 'login': login, 'password': psw}:
port = 22 # Дефолтный порт
case _: # Если данные не подходят
return "error connection"
return f"connection: {host}@{login}.{psw}:{port}"
Теперь код стал чище, и мы избавились от дублирования. Если первые два
case сработают, то переменные
host, login, psw и port будут доступны за пределами
match. Если ни один case не подойдет, функция вернет ошибку.
Обработка данных о книгах: еще один пример
Теперь представим, что у нас есть данные о книгах в разных форматах:
book_1 = ("Юн Цуй", "Рецепты Python", 2022)
book_2 = ["Юн Цуй", "Рецепты Python", 2022, 3432.27]
book_3 = {'author': "Юн Цуй", 'title': "Рецепты Python", 'year': 2022}
book_4 = {'author': "Юн Цуй", 'title': "Рецепты Python", 'price': 3432.27, 'year': 2022}
Наша задача — написать функцию
book_to_tuple(), которая приведет все эти данные к одному формату: (автор, название, год, цена). Вот как это можно сделать:
def book_to_tuple(data: dict | tuple | list) -> tuple | None:
match data:
case author, title, year:
price = None # Если цена не указана
case author, title, year, price, *_:
pass # Игнорируем лишние данные
case {'author': author, 'title': title, 'year': year, 'price': price}:
pass
case {'author': author, 'title': title, 'year': year}:
price = None # Если цена не указана
case _: # Если данные не подходят
return None
return author, title, year, price
Здесь мы обрабатываем разные форматы данных: кортежи, списки и словари. Если цена не указана, она становится
None. Если данные не подходят ни под один шаблон, функция вернет
None.
Усложняем задачу: проверка года
Теперь добавим проверку на то, что год издания должен быть в диапазоне от
min_year до
max_year. Сначала сделаем это "в лоб":
def book_to_tuple(data: dict | tuple | list, min_year=1800, max_year=3000) -> tuple | None:
price = None
match data:
case author, title, int(year) if min_year < year < max_year:
pass
case author, title, int(year), price, *_ if min_year < year < max_year:
pass
case {'author': author, 'title': title, 'year': int(year), 'price': price} if min_year < year < max_year:
pass
case {'author': author, 'title': title, 'year': int(year)} if min_year < year < max_year:
pass
case _:
return None
return author, title, year, price
Но тут видно, что проверка года дублируется в каждом
case. Чтобы избежать этого, можно вынести проверку за пределы
match:
def book_to_tuple(data: dict | tuple | list, min_year=1800, max_year=3000) -> tuple | None:
price = None
match data:
case author, title, int(year):
pass
case author, title, int(year), price, *_:
pass
case {'author': author, 'title': title, 'year': int(year), 'price': price}:
pass
case {'author': author, 'title': title, 'year': int(year)}:
pass
case _:
return None
if not (min_year < year < max_year):
return None
return author, title, year, price
Теперь код стал чище, и мы избежали дублирования.
Фишка с константами в match/case
Теперь немного о фишках. Предположим, у вас есть переменная cmd, и вы хотите проверить ее значения:
cmd = 10
match cmd:
case 3:
print("3")
case 5:
print("5")
Но использовать "магические числа" (типа 3 и 5) — плохая практика. Лучше использовать константы:
CMD_3 = 3
CMD_5 = 5
cmd = 3
match cmd:
case CMD_3:
print("3")
case CMD_5:
print("5")
Но тут возникает проблема: Python не позволяет использовать переменные как константы в
case. Чтобы обойти это, можно использовать хитрость с импортом или классом:
import consts # Файл с константами
cmd = 3
match cmd:
case consts.CMD_3:
print("3")
case consts.CMD_5:
print("5")
Или так:
class Consts:
CMD_3 = 3
CMD_5 = 5
cmd = 3
match cmd:
case Consts.CMD_3:
print("3")
case Consts.CMD_5:
print("5")
Итог
Конструкция match/case — это мощный инструмент, который позволяет писать более читаемый и лаконичный код. Она особенно полезна, когда нужно обрабатывать разные форматы данных или проверять множество условий. Главное — не бояться экспериментировать и использовать фишки Python на полную катушку!
Удачи в кодинге, и помните: чем чище код, тем меньше багов! 🚀
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ