Найти тему
Nuances of programming

Долгожданные инструкции Switch-Case в Python

Оглавление

Источник: 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 .

-2

Сразу становится очевидным, что “да”, можно выстроить ту же логику, используя набор инструкций 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, то очевидно, что она состоит из нескольких уровней, и это потребуется учесть при парсинге:

Обучающий датасет в формате JSON
Обучающий датасет в формате JSON

Проблема же в том, что не все образцы используют одинаковый формат словаря.

Если взглянуть на несколько последних, то мы видим, что список qas содержит и answers , и plausible_answers , в то время как в предыдущих образцах присутствуют только answers :

Последняя запись этого датасета представляет другой формат словаря (используемый несколькими записями в файле)
Последняя запись этого датасета представляет другой формат словаря (используемый несколькими записями в файле)

Попробуем с помощью match-case создать более чистую альтернативу тяжелой логике if-else , необходимой для обработки всего этого. Сначала загружаем данные:

Загружаем данные с помощью json.load
Загружаем данные с помощью json.load

Данный 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 , сообщество быстро выработает определенный консенсус и оптимальные подходы к реализации.

Ну а пока, этот вариант просто выглядит круто  —  я восхищен!

Спасибо за внимание!

Читайте также:

Читайте нас в Telegram , VK

Перевод статьи James Briggs: Switch-Case Statements Are Coming to Python