Источник: Nuances of Programming
Python 3.10 обрел немало интересных возможностей, одна из которых привлекла мое внимание в особенности — структурное сопоставление с шаблоном, иначе говоря инструкции switch/case .
Несмотря на свою повсеместность в большинстве языков, в Python инструкции switch до сих пор отсутствовали.
Еще в 2006 году создавалось предложение PEP 3103, в котором рекомендовалось реализовать поддержку инструкций switch-case . Однако в результате опроса на PyCon 2007 эта функция не получила достаточной поддержки, и разработчики ее отложили.
Гораздо позднее уже в 2020 году Гвидо Ван Россум , создатель Python, опубликовал первую документацию, описывающую новые инструкции switch , технику, которая, согласно PEP 634, была названа как структурное сопоставление с шаблоном.
Однако, как вы вскоре увидите, здесь нам предлагается намного большее, нежели просто инструкции switch-case (что подразумевает match-case ).
Посмотрим, как эта логика работает.
1. Структурное сопоставление с шаблоном
Сопоставление подразумевает определение при операторе match искомого значения, после которого можно перечислить несколько потенциальных кейсов, каждый с оператором case . В месте обнаружения совпадения между match и case выполняется соответствующий код.
Например:
Здесь происходит проверка нескольких условий и выполнение разных операций на основе значения, которое мы находим внутри http_code .
Сразу становится очевидным, что “да”, можно выстроить ту же логику, используя набор инструкций if-elif-else :
Тем не менее, с помощью инструкций match-case мы избавляемся от повторения http_code == , что повышает чистоту кода при тестировании на соответствие многим разным условиям.
Другой пример
В PEP 635 есть отличные примеры инструкций match-case , повышающих читаемость кода. Один из этих примеров показывает, как использовать эту инструкцию для проверки типа и структуры субъекта:
match x:
case host, port:
mode = "http" case host, port, mode:
pass
Здесь мы ожидаем получения деталей соединения в формате кортежа и присваиваем данные значения правильным переменным.
В этом случае, если mode соединения в кортеже не определен (например, было передано только два значения — host и port ), мы предполагаем, что режим соединения http .
Тем не менее в других случаях можно ожидать, что режим будет определен явно. Тогда вместо этого мы получаем кортеж, наподобие (<host>, <port>, "ftp") , и mode уже не устанавливается как http .
Если же мы пропишем ту же логику с помощью if-else , то получится вот что:
if isinstance(x, tuple) and len(x) == 2 :
host, port = x
mode = "http" elif isinstance(x, tuple) and len(x) == 3 :
host, port, mode = x
Предпочесть можно любой из этих вариантов, но лично для меня реализация через match-case выглядит намного чище.
Реальный пример с форматом JSON
Еще один интересный случай — это способность по-разному парсить объекты словаря в зависимости от их структуры. Отличным тестовым примером будет парсинг датасета SQuAD 2.
Этот датасет представляет чрезвычайно популярный набор пар вопрос-ответ, используемых для обучения моделей МО отвечать на вопросы. Скачать его можно так:
Если взглянуть на структуру SQuAD, то очевидно, что она состоит из нескольких уровней, и это потребуется учесть при парсинге:
Проблема же в том, что не все образцы используют одинаковый формат словаря.
Если взглянуть на несколько последних, то мы видим, что список qas содержит и answers , и plausible_answers , в то время как в предыдущих образцах присутствуют только answers :
Попробуем с помощью match-case создать более чистую альтернативу тяжелой логике if-else , необходимой для обработки всего этого. Сначала загружаем данные:
Данный JSON-файл содержит несколько слоев. После обращения к squad['data'] нужно перебрать каждую group вопросов, затем каждый paragraph , а затем все qas (вопрос-ответы). Выглядеть это будет так:
for group in squad['data' ]:
for paragraph in group ['paragraphs' ]:
for qa in paragraph['qas' ]:
# вставить код сюда
А здесь начинается самое интересное. Используя логику if-else , мы получим следующее:
Не очень красиво, но работает. Теперь перепишем все это с помощью match-case :
Определенно выглядит менее загруженно и является отличной альтернативой изначальному варианту логики парсинга.
Лично я считаю, что этот новый синтаксис очень неплох, хотя использую его 50/50. Уверен, как только больше пользователей начнут применять match-case , сообщество быстро выработает определенный консенсус и оптимальные подходы к реализации.
Ну а пока, этот вариант просто выглядит круто — я восхищен!
Спасибо за внимание!
Читайте также:
Перевод статьи James Briggs: Switch-Case Statements Are Coming to Python