{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Блог об аналитике, визуализации данных, data science и BI, заметки с тегом: english",
    "home_page_url": "http:\/\/test.leftjoin.ru\/tags\/english\/",
    "feed_url": "http:\/\/test.leftjoin.ru\/tags\/english\/json\/",
    "icon": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg",
    "author": {
        "name": "Николай Валиотти",
        "url": "http:\/\/test.leftjoin.ru\/",
        "avatar": "http:\/\/test.leftjoin.ru\/user\/userpic@2x.jpg"
    },
    "items": [
        {
            "id": "108",
            "url": "http:\/\/test.leftjoin.ru\/all\/pattern-matching-v-python\/",
            "title": "В Python 3.10 появился pattern matching",
            "content_html": "<p class=\"note\">Этот материал — перевод статьи <a href=\"https:\/\/www.infoworld.com\/article\/3609208\/how-to-use-structural-pattern-matching-in-python.html\" class=\"nu\">«<u>How to use structural pattern matching in Python<\/u>»<\/a><\/p>\n<p>В новом релизе Python 3.10 появились операторы <span class=\"inline-code\">case\/match<\/span>, которые отвечают за реализацию в языке синтаксиса pattern-matching.<\/p>\n<p>Python, несмотря на его простоту и популярность, в отличие от других языков, не имел отдельной формы управления потоком (form of flow control) — способа взять значение и элегантно сопоставить его с одним из множества возможных условий. В C и C++ эта функция реализована конструкцией <span class=\"inline-code\">switch\/case<\/span>, а в Rust она называется pattern matching.<\/p>\n<p>Изящных способов реализовать это в Python, кроме как воспользоваться конструкцией <span class=\"inline-code\">if\/elif\/else<\/span> и поиском по словарю, до этого момента не существовало. Оба способа работают, но из-за своей громоздкости они могли затруднить читабельность кода.<\/p>\n<p>За последние годы были предприняты несколько попыток включить синтаксис типа <span class=\"inline-code\">switch\/case<\/span> в Python, но все они <a href=\"https:\/\/www.infoworld.com\/article\/3563840\/python-may-get-pattern-matching-syntax.html\">провалились<\/a>. Это первая реализация структурного сопоставления шаблонов (structural pattern matching), которая сейчас доступна только в версии для разработчиков.<\/p>\n<h2>Введение в pattern matching на Python<\/h2>\n<p>Структурное сопоставление шаблонов (structural pattern matching) вводит оператор <span class=\"inline-code\">match\/case<\/span>, который работает по той же схеме, что и <span class=\"inline-code\">switch\/case<\/span>. Оператор проверяет объект на соответствие одному или нескольким шаблонам и, если совпадение найдено, выполняет действие.<\/p>\n<pre class=\"e2-text-code\"><code>match command:\r\n    case &quot;quit&quot;:\r\n        quit()\r\n    case &quot;reset&quot;:\r\n        reset()\r\n    case unknown_command:\r\n        print (f&quot;Unknown command'{unknown_command}'&quot;)<\/code><\/pre><p>За каждым выражением <span class=\"inline-code\">case<\/span> следует шаблон для сопоставления. В данном примере сверху вниз идет сопоставление строк с оператором, и если такое сопоставление найдено, оператор выполняется. Также можно захватить все или часть совпадения и повторно использовать их. В нашем примере в случае с шаблоном сопоставления <span class=\"inline-code\">unknown_command<\/span> мы использовали его повторно внутри f-строки.<\/p>\n<h2>Сопоставление переменных с помощью pattern matching<\/h2>\n<p>Если вы хотите сопоставить значение с константами, то константы следует отнести к полям класса:<\/p>\n<pre class=\"e2-text-code\"><code>class Command:\r\n    QUIT = 0\r\n    RESET = 1\r\n\r\ncommand = 0\r\n\r\nmatch command:\r\n    case Command.QUIT:\r\n        quit()\r\n    case Command.RESET:\r\n        reset()<\/code><\/pre><p>Если вы попробуете сделать это не прибегая к классам, например, так:<\/p>\n<pre class=\"e2-text-code\"><code>QUIT = 0\r\nRESET = 1\r\n\r\ncommand = 0\r\nmatch command:\r\n    case QUIT:\r\n        quit()\r\n    case RESET:\r\n        reset()<\/code><\/pre><p>Получите в ответ ошибку, связанную с тем, что имя не относится к известному паттерну:<\/p>\n<pre class=\"e2-text-code\"><code>name capture 'QUIT' makes remaining patterns unreachable<\/code><\/pre><h2>Сопоставление нескольких элементов с помощью pattern matching<\/h2>\n<p>Pattern matching используется не только как замена поиска по словарю. Оно используется для описания самой структуры того, что вы хотите сопоставить. Таким образом, вы можете выполнять сопоставления на основе количества сопоставляемых элементов или их комбинаций.<\/p>\n<p>Вот более сложный пример. Здесь пользователь вводит команду, за которой, возможно, следует имя файла:<\/p>\n<pre class=\"e2-text-code\"><code>command = input()\r\nmatch command.split():\r\n    case [&quot;quit&quot;]:\r\n        quit()\r\n    case [&quot;load&quot;, filename]:\r\n        load_from(filename)\r\n    case [&quot;save&quot;, filename]:\r\n        save_to(filename)\r\n    case _:\r\n        print (f&quot;Command '{command}' not understood&quot;)<\/code><\/pre><p>Давайте рассмотрим варианты case по порядку:<\/p>\n<ul>\n<li><span class=\"inline-code\">case [’quit’]:<\/span> проверяет, соответствует ли то, что мы сопоставляем, списку только с элементом <span class=\"inline-code\">’quit’<\/span>, полученных после разделения введенных данных с помощью <span class=\"inline-code\">split()<\/span>.<\/li>\n<li><span class=\"inline-code\">case [’load’, filename]:<\/span> проверяет, является ли первый разделенный элемент строкой <span class=\"inline-code\">’load’<\/span>, и следует ли за ней вторая строка. Если вторая строка есть, то вторая строка сохраняется в переменной <span class=\"inline-code\">filename<\/span> и используется для дальнейшей работы. Аналогично проверяется case <span class=\"inline-code\">[«save», filename]:<\/span>.<\/li>\n<li><span class=\"inline-code\">case _: <\/span> это совпадение с подстановочным знаком (wildcard match). Происходит совпадение, если до этого момента не происходило никакого другого совпадения. Обратите внимание, что символ нижнего подчеркивания ( _ ) ни к чему не привязан, в данном случае нижнее подчеркивание используется как сигнал команде <span class=\"inline-code\">match<\/span>, что рассматриваемый случай является подстановочным знаком (wildcard). (Вот почему мы ссылаемся на команду переменной в теле блока case, ведь ничего не было захвачено.)<\/li>\n<\/ul>\n<h2>Шаблоны в structural pattern matching<\/h2>\n<p>Шаблоны могут быть простыми значениями или содержать более сложную логику сопоставления.<br \/>\nВот несколько примеров:<\/p>\n<ul>\n<li><span class=\"inline-code\">case ’a’:<\/span> сопоставить с единственным значением <span class=\"inline-code\">’a’<\/span>.<\/li>\n<li><span class=\"inline-code\">case [’a’,’b’]:<\/span> сопоставить с коллекцией (collection) <span class=\"inline-code\">[’a’,’b’]<\/span>.<\/li>\n<li><span class=\"inline-code\">case [’a’, value1]:<\/span> сопоставить с коллекцией, в которой два значения, и поместить второе значение в переменную  <span class=\"inline-code\">value1<\/span>.<\/li>\n<li><span class=\"inline-code\">case [’a’, *values]:<\/span> сопоставить с коллекцией, в которой как минимум одно значение. Остальные значения, если они есть, хранить в <span class=\"inline-code\">values<\/span>. Обратите внимание, что вы можете включить только один элемент со звездочкой в шаблон.<\/li>\n<li><span class=\"inline-code\">case (’a’|’b’|’c’):<\/span> Оператор <span class=\"inline-code\">or<\/span>, он же <span class=\"inline-code\">|<\/span>, может использоваться для обработки нескольких обращений в одном блоке case. Здесь мы сопоставляем <span class=\"inline-code\">’a’<\/span>, <span class=\"inline-code\">’b’<\/span>, или <span class=\"inline-code\">’c’<\/span>.<\/li>\n<li><span class=\"inline-code\">case (’a’|’b’|’c’) as letter:<\/span> То же, что и выше, за исключением того, что теперь мы помещаем соответствующий элемент в переменную <span class=\"inline-code\">letter<\/span>.<\/li>\n<li><span class=\"inline-code\">case [’a’, value] if <expression>:<\/span> Переменная связывается только если <span class=\"inline-code\">expression<\/span> истинно. Переменные, которые мы хотим связать, можно использовать в <span class=\"inline-code\"><expression><\/span>. Например, если мы используем <span class=\"inline-code\">if value in valid_values<\/span>, то <span class=\"inline-code\">case<\/span> будет действительным только в том случае, если захваченное значение <span class=\"inline-code\">value<\/span> был на самом деле в коллекции <span class=\"inline-code\">valid_values<\/span>.<\/li>\n<li><span class=\"inline-code\">case [’z’, _]:<\/span> будет соответствовать любая коллекция элементов, которая начинается с <span class=\"inline-code\">’z’<\/span>.<\/li>\n<\/ul>\n<h2>Сопоставление с объектами с помощью pattern matching<\/h2>\n<p>Самая продвинутая функция pattern matching в Python — это возможность сопоставлять объекты с определенными свойствами. Рассмотрим приложение, в котором  мы работаем с объектом <span class=\"inline-code\">media_object<\/span>.  Этот объект мы хотим преобразовать в файл <span class=\"inline-code\">.jpg<\/span>  и вернуть из функции.<\/p>\n<pre class=\"e2-text-code\"><code>match media_object:\r\n    case Image(type=&quot;jpg&quot;):\r\n        # Return as-is\r\n        return media_object\r\n    case Image(type=&quot;png&quot;) | Image(type=&quot;gif&quot;):\r\n        return render_as(media_object, &quot;jpg&quot;)\r\n    case Video():\r\n        raise ValueError(&quot;Can't extract frames from video yet&quot;)\r\n    case other_type:\r\n        raise Exception(f&quot;Media type {media_object} can't be handled yet&quot;)<\/code><\/pre><p>В каждом из описанных выше <span class=\"inline-code\">case<\/span> мы ищем объект определенного типа, иногда с определенными атрибутами. В первом <span class=\"inline-code\">case<\/span> ищем соответствие объекта <span class=\"inline-code\">Image<\/span> , у которого <span class=\"inline-code\">type<\/span> атрибутирован как <span class=\"inline-code\">’jpg’<\/span>. Во втором <span class=\"inline-code\">case<\/span> идет сопоставление, если <span class=\"inline-code\">type<\/span> соответствует <span class=\"inline-code\">’png’<\/span>> или <span class=\"inline-code\">’gif’<\/span>. В третьем <span class=\"inline-code\">case<\/span> идет проверка на соответствие объекта типу <span class=\"inline-code\">Video<\/span>, при этом атрибут не имеет значения. И в последнем случае мы получаем все, что не было выбрано ранее.<\/p>\n<p>Вы также можете выполнять захват с сопоставлением объектов:<\/p>\n<pre class=\"e2-text-code\"><code>match media_object:\r\n    case Image(type=media_type):\r\n        print (f&quot;Image of type {media_type}&quot;)<\/code><\/pre><h2>Эффективное использование pattern matching<\/h2>\n<p>Ключевой момент при работе с <span class=\"inline-code\">match\/case<\/span> в Python заключается в написании шаблонов, в которых будет описана структура того, с чем вы хотите работать. Простые тесты на константы хороши, но если это все, что вы делаете, то лучше просто сделать поиск по словарю. Настоящая ценность структурного сопоставления с шаблоном (structural pattern matching) в Python заключается в возможности сопоставления с шаблоном объекта, а не только с каким-то одним объектом или даже с их набором.<\/p>\n<p>Еще одна важная деталь, которую нужно иметь в виду, это порядок написания сопоставлений. То, какие сопоставления вы проверите в первую очередь, повлияет на эффективность и точность вашего сопоставления в целом. Размещайте наиболее конкретные сопоставления на первом месте, а наиболее общие — на последнем.<\/p>\n<p>В конечном счете, если у вас есть проблема, которую можно решить с помощью <span class=\"inline-code\">if\/elif\/else<\/span> или поиска по словарю, то используйте их вместо <span class=\"inline-code\">match\/case<\/span>. Pattern matching является мощным, но не универсальным решением. Используйте его, когда это наиболее целесообразно.<\/p>\n<p>Подробнее с документацией по pattern matching в Python (PEP 622) можно ознакомиться <a href=\"https:\/\/www.python.org\/dev\/peps\/pep-0622\/\">тут<\/a>.<\/p>\n",
            "date_published": "2021-05-06T13:42:07+03:00",
            "date_modified": "2021-05-10T13:18:17+03:00",
            "_date_published_rfc2822": "Thu, 06 May 2021 13:42:07 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "108",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "31",
            "url": "http:\/\/test.leftjoin.ru\/all\/angliyskaya-versiya-bloga\/",
            "title": "Английская версия блога",
            "content_html": "<p>С недавних пор блог Left Join стал доступен <a href=\"https:\/\/www.valiotti.com\/leftjoin\">на английском языке<\/a>. Пока готова только треть текущего контента и английский блог постепенно наполняется.<\/p>\n<p>Соответствующая ссылка появилась в правом верхнем углу этого блога.<br \/>\nБуду благодарен вашим комментариям по текстам на английском языке :)<\/p>\n",
            "date_published": "2020-01-19T15:53:37+03:00",
            "date_modified": "2020-01-19T15:53:20+03:00",
            "_date_published_rfc2822": "Sun, 19 Jan 2020 15:53:37 +0300",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "31",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        }
    ],
    "_e2_version": 3365,
    "_e2_ua_string": "E2 (v3365; Aegea)"
}