DevGang
Авторизоваться

Понимание вариантов использования сопоставления с образцом

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

Однако тем из нас, кто новичок в Pattern Matching, сложно определить правильные варианты использования, и поэтому код, который мы пишем, мало чем отличается от if-else, с немного большим синтаксическим сахаром в коде if-else, чтобы обеспечить более детальное определение переменных.

Чтобы понять реальный вариант использования сопоставления с образцом, нам нужно просмотреть параграф в PEP 635.

Большая часть возможностей сопоставления с образцом заключается в вложении подшаблонов. Таким образом, краеугольным камнем дизайна является то, что успех сопоставления с образцом напрямую зависит от успеха подшаблона.

Вложенность подшаблонов звучит немного абстрактно. Каковы практические примеры этого свойства?

Самая простая для понимания структура данных — это дерево.

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

class TreeNode:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

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

AST Дерево

Дерево AST — это очень распространенный метод, используемый для проверки синтаксиса или проверки.

Предположим, у нас есть требование проверить, есть ли в исходном коде прямой вызов print, тогда мы можем использовать if, чтобы сравнить условия и выяснить, нарушает ли узел, удовлетворяющий условию, правило проверки.

for node in ast.walk(tree):
    if (
        isinstance(node, ast.Call)  # It's a call
        and isinstance(node.func, ast.Name)  # It directly invokes a name
        and node.func.id == 'print'  # That name is `print`
    ):
        sys.exit(0)

sys.exit(1)

Из приведенного выше кода мы знаем, что хотим сопоставить узел ast.Call, и это функция вызова, а имя функции — print, всего три условия.

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

for node in ast.walk(tree):
    match node:
        # If it's a call to `print`
        case ast.Call(func=ast.Name(id='print')):
            sys.exit(0)

sys.exit(1)

С помощью сопоставления с образцом мы можем сделать условия более простыми, сравнив их с определением class, которое есть у нас в голове.

Из кода мы видим, что сопоставление с образцом упрощает сравнение условий, но в этом не вся сила Pattern Matching, поскольку мы еще не сравнивали вложенные структуры. Давайте посмотрим на следующий пример.

Парсинг дерева

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

Имея такое дерево, я хочу знать:

  • Есть ли на дереве зеленый квадрат с красным кружком, прикрепленным к левому узлу?
  • Имеет ли дерево форму любого цвета с желтым треугольником, прикрепленным к левому узлу, и синим прямоугольником, прикрепленным к правому узлу?
  • Дерево имеет желтый круг с синим прямоугольником, прикрепленным к левому узлу. Для синего прямоугольника левый узел соединен с красным треугольником, а правый узел соединен с красным прямоугольником. Красный прямоугольник, правый узел соединен с зеленым квадратом.

Тогда наша модель мышления будет выглядеть так, как показано на следующей диаграмме.

Собственно, это все, что должна делать наша программа.

def Find(Tree):
  match Tree:
    case Square('green' , 
            Circle('red') as left , 
            _
          ) as root:
            print(f'case1 \n  {root = } \n {left = } \n ')

    case Geometric( _ , 
              Triangle('yellow') as left,
              Rectangle('blue')  as right,
            ):
            print(f'case2 \n {left = } \n {right = } \n')

    case Circle('yellow', 
             _ ,
             Rectangle('blue',
                Triangle('red'),
                Rectangle('red',
                    _ ,
                    Square('green')
                ),
             ) as right
          ) as root:
            print(f'case3 \n {root = } \n {right = } \n ')

    case _:
            print('Not Found \n')

Из этого примера мы можем увидеть силу сопоставления с образцом не только для сравнения узлов с явными условиями, но и для сравнения нечетких условий, как в случае 2. Не только легче писать код, но и легче отображать идеи, которые у нас есть в наша голова прямо к коду.

Фактически, оптимизаторы баз данных и механизмов больших данных активно используют сопоставление с образцом (не в Python), поскольку шаблоны, которым оптимизаторы должны сопоставлять, настолько сложны, что было бы очень сложно поддерживать код, который просто использует if-else.

Заключение

Сопоставление с образцом — это мощный метод, это не просто if-else или switch-case, это pattern matching.

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

Вот классический пример из Stack Overflow. Я запечатлел ответ, набравший наибольшее количество лайков:

match a:
    case _ if a < 42:
        print('Less')
    case _ if a == 42:
        print('The answer')
    case _ if a > 42:
        print('Greater')

Действительно ли это лучше, чем if-else?

if a < 42:
    print('Less')
elif a == 42:
    print('The answer')
elif a > 42:
    print('Greater')

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

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

Ссылки

Источник:

#Python
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу