В Python 3.10 имплементирован своего рода оператор switch — что-то вроде него. Оператор switch в других языках, таких как C или Java, выполняет простой матчинг значения переменной и исполняет код в зависимости от этой величины.

Он может использоваться просто, как обычный оператор switch, но способен на гораздо большее.

Возможно, этого было бы достаточно для языка C, но ведь речь о Python, а в Python 3.10 реализована гораздо более мощная и гибкая конструкция, называемая структурным сопоставлением шаблона. Она может использоваться как простой оператор switch, но способна на гораздо большее.

Давайте рассмотрим несложный пример с оператором switch. Ниже приведен сниппет, который осуществляет выбор одного значения. Мы проверим его, запустив в цикле со значениями 1,2,3 и 4.

for thing in [1,2,3,4]:
    match thing:
        case 1:
            print("thing is 1")
        case 2:
            print("thing is 2")
        case 3:
            print("thing is 3")
        case _:
            print("thing is not 1, 2 or 3")

Первое, что бросается в глаза, — это аккуратность синтаксиса. Он начинается с ключевого слова match, за которым следует имя переменной. Затем идет список кейсов, начинающийся с case и сопровождающийся значением, которое сопоставляется. Обратите внимание на использование двоеточий и отступов.

Это не отличается от оператора switch/case в других языках, но в отличие, например, от языка C, после исполнения кода для конкретного кейса проверка переходит к завершению оператора match.

Если совпадения нет, то происходит выполнение кода в случае по умолчанию, обозначенном символом -.

И вот результат.

thing is 1
thing is 2
thing is 3
thing is not 1, 2 or 3

В этом нет ничего удивительного.

Оператор switch — это простой кейс матчинга шаблона, но Python идет немного дальше. Взгляните на этот код:

for thing in [[1,2],[9,10],[1,2,3],[1],[0,0,0,0,0]]:
    match thing:
        case [x]:
            print(f"single value: {x}")
        case [x,y]:
            print(f"two values: {x} and {y}")
        case [x,y,z]:
            print(f"three values: {x}, {y} and {z}")       
        case _:
            print("too many values")

Это снова оператор match в цикле, но на этот раз в качестве перечня значений, которые цикл будет итерировать, выступают сами списки — сначала [1,2] затем [9,10] и так далее.

Операторы case пытаются выполнить матчинг этих списков. Первый case соответствует списку с одним элементом, второй — списку с двумя элементами, третий — списку с тремя элементами. Последний case используется по умолчанию.

Но он делает больше, чем это. Он также выполняет биндинг значений, которые сопоставляются с идентификаторами в операторе case. Так, например, первый список — это [1,2], и он соответствует второму случаю [x,y]. Таким образом, в выполняемом коде идентификаторы x и y принимают значения 1 и 2, соответственно. Совсем неплохо, правда?

Итак, результат таков:

two values: 1 and 2
two values: 9 and 10
three values: 1, 2 and 3
single value: 1
too many values

Из нашей первой несложной программы мы знаем, что можно выполнять матчинг значений, а из приведенной выше — матчинг других, более общих шаблонов. Итак, можем ли мы делать матчинг шаблонов, включающих значения? Конечно!

for thing in [[1,2],[9,10],[3,4],[1,2,3],[1],[0,0,0,0,0]]:
    match thing:
        case [x]:
            print(f"single value: {x}")
        case [1,y]:
            print(f"two values: 1 and {y}")
        case [x,10]:
            print(f"two values: {x} and 10")
        case [x,y]:
            print(f"two values: {x} and {y}")
        case [x,y,z]:
            print(f"three values: {x}, {y} and {z}")       
        case _:
            print("too many values")

Например, во втором кейсе мы осуществляем матчинг списка, состоящего из двух элементов, первый из которых имеет значение 1.

Вот результат:

two values: 1 and 2
two values: 9 and 10
two values: 3 and 4
three values: 1, 2 and 3
single value: 1
too many values

Но это еще не все.

Вот программа, которая будет выполнять матчинг списка с любым количеством элементов.

for thing in [[1,2,3,4],['a','b','c'],"this won't be matched"]:
    match thing:
        case [*y]:
            for i in y:
                print(i)
        case _:
            print("unknown")

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

1
2
3
4
a
b
c
unknown

Это еще не все, но, надеюсь, данная статья дала вам представление о структурном сопоставлении шаблона в Python 3.10.

Более расширенно о дополнительном способе матчинга шаблона я писал здесь.

На сайте Python.org есть полное описание структурного сопоставления шаблона, включая учебное руководство, в PEP 636. Учебник довольно хороший, и я советую вам его прочитать.

В Python 3.10 довольно много новых разработок, помимо структурного матчинга шаблона. О них рассказывается в нескольких статьях, например, см. Джеймс Бриггс Новые возможности в Python 3.10.

Однако имейте в виду, что 3.10 еще только бета-версия, и хотя примеры, которые я показал выше, работают отлично, вам не следует использовать Python 3.10 со всей серьезностью до его официального релиза.


Приглашаем всех заинтересованных на открытое занятие «Знакомство с веб разработкой на Flask». На нем познакомимся с основами веб разработки на Flask, а также научимся создавать и рендерить шаблоны страниц. Попробуем создать Flask приложение, затем создать роуты и в конце обработать различные HTTP методы на Flask. Регистрирация — по ссылке.

Комментарии (10)


  1. Jury_78
    06.05.2022 15:45
    -3

    switch в других языках, таких как C или Java, выполняет простой матчинг значения переменной

    Понимаю сленг, но по мне как то уж совсем... Раньше переводилось как переключатель.


    1. Roman_Cherkasov
      06.05.2022 16:27

      Кто ж это умудрился то, переводить языковые конструкции (зарезервированные слова)?

      Ааа. Не про то подумал.


    1. DistortNeo
      06.05.2022 16:27
      +5

      Меня тоже коробит. Лучше либо писать без перевода: "pattern matching", либо "сопоставление шаблонов", а про слово "матчинг" забыть. А фраза "простой кейс матчинга" вообще убивает наповал: "кейс" используется то в значении "случай", то в значении "оператор case".

      P.S. К слову, в C# оператор switch тоже поддерживает pattern matching.


      1. impwx
        08.05.2022 14:08
        +1

        "Сопоставление с образцом" же


    1. dopusteam
      06.05.2022 17:24
      +1

      Покажите статью, где используется термин "переключатель"


      1. Jury_78
        06.05.2022 19:20
        -1

        Подходит? Б. Керниган, Д. Ритчи // Язык программирования Си, Глава 3.4 Переключатель switch


        1. dopusteam
          06.05.2022 20:39
          +1

          Ну вроде там используется термин "переключатель switch", а не "переводится как переключатель"


  1. Nicknnn
    06.05.2022 17:22

    Последний пример не очевиден. Ведь строка тоже в своём роде list. Но результат другой. Значит вначале сопоставляется тип, а затем данные?


    1. egorro_13
      06.05.2022 20:53

      Строка - это все же не list, а другой, тоже итерируемый, тип, а синтаксис [...] относится именно к спискам как к конкретному типу. Другое дело - что сам по себе синтаксис этого switch-а как-то неочевиден, по приведенным примерам больше напрашивается в голове что-то такое:

      y = (1, 2, 3, 4)
      for thing in [[1,2,3,4],['a','b','c'],"this won't be matched"]:
           match thing:
               case [*y]: # совпадение для [1, 2, 3, 4]
                	...


  1. khajiit
    06.05.2022 21:14
    +6

    Однако имейте в виду, что 3.10 еще только бета-версия, и хотя примеры, которые я показал выше, работают отлично, вам не следует использовать Python 3.10 со всей серьезностью до его официального релиза.

    3.10.4 передает привет.