{"id":329466,"date":"2023-05-29T15:06:00","date_gmt":"2023-05-29T15:06:00","guid":{"rendered":"http:\/\/itteacheritfreelance.hk\/wordpress\/?guid=c2bff812d5ec5d689944ac5c3641a3a7"},"modified":"2023-05-29T15:06:00","modified_gmt":"2023-05-29T15:06:00","slug":"the-python-language-summit-2023-pattern-matching-__match__-and-view-patterns","status":"publish","type":"post","link":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/2023\/05\/29\/the-python-language-summit-2023-pattern-matching-__match__-and-view-patterns\/","title":{"rendered":"The Python Language Summit 2023: Pattern Matching, __match__, and View Patterns"},"content":{"rendered":"<p class=\"syndicated-attribution\"><meta name= \\\"keywords \\\" content= \\\"\u96fb\u5b50\u8a08\u7b97\u6a5f, \u6559\u80b2, IT \u96fb\u8166\u73ed,\u96fb\u8166\u88dc\u7fd2\uff0c \u96fb\u8166\u73ed\uff0c \u5bb6\u6559\uff0c \u79c1\u4eba\u8001\u5e2b\uff0c \u8cc7\u8a0a\u6280\u8853\uff0c \u7a0b\u5e8f\u8a2d\u8a08\uff0c \u96fb\u5b50\u8a08\u7b97\u6a5f\uff0c \u904a\u6232\uff0c \u860b\u679c\uff0c \u96fb\u5f71\uff0c \u8a08\u7b97\u6a5f\uff0c\u7de8\u78bc\uff0c Java\uff0c C\/C++\uff0c JavaScript\uff0c PHP\uff0c HTML\uff0c CSS\uff0c MySQL\uff0c mobile\uff0c Android\uff0c \u52d5\u6f2b\uff0c Python\uff0c teacher\uff0c \u88dc\u7fd2\uff0c \u96fb\u8166\u88dc\u7fd2 \u8cc7\u8a0a, \u7535\u5b50\u8ba1\u7b97\u673a, IT ,Game, apple, movie, Computer,student,Java,\u6559\u80b2, ,\u5b66\u751f, \u5b66\u4e60, learn, \u6559\u5b66,  Android, apple,anime, animation, \u4fe1\u606f\u6280\u672f, \u7a0b\u5e8f\u8bbe\u8ba1, \u79fb\u52a8\u7535\u8bdd, \u8cc7\u8a0a\u79d1\u6280,Game, Jeu, Juego,Call Of Duty ,\u4f7f\u547d\u53ec\u559a , \u6e38\u620f, \u7535\u5b50\u6e38\u620f,, \u591a\u4eba\u7535\u5b50\u6e38\u620f, \u7f51\u7edc\u6e38\u620f\uff0conline\uff0conline game, \u624b\u673a\u6e38\u620f, mobile \\\"><\/p>\n<div class=\"markdown-body container-fluid comment-inner comment-enabled\" data-hard-breaks=\"true\" id=\"doc\">One of the most exciting new features in Python 3.10 was <a href=\"https:\/\/docs.python.org\/3\/whatsnew\/3.10.html#pep-634-structural-pattern-matching\">the introduction of pattern matching<\/a> (introduced in PEPs <a href=\"https:\/\/peps.python.org\/pep-0634\/\">634<\/a>, <a href=\"https:\/\/peps.python.org\/pep-0635\/\">635<\/a> and <a href=\"https:\/\/peps.python.org\/pep-0636\/\">636<\/a>). Pattern matching has a wide variety of uses, but really shines in situations where you need to undergo complex destructurings of tree-like datastructures.<\/p>\n<p><span>That\u2019s a lot of words which may or may not mean very much to you \u2013 but consider, for example, using <\/span><a href=\"https:\/\/docs.python.org\/3\/library\/ast.html\" rel=\"noopener\" ><span>the <\/span><code>ast<\/code><span> module<\/span><\/a><span> to parse Python source code. If you\u2019re unfamiliar with the <\/span><code>ast<\/code><span> module: the module provides tools that enable you to compile Python source code into an \u201cabstract syntax tree\u201d (AST) representing the code\u2019s structure. The Python interpreter itself converts Python source code into an AST in order to understand how to run that code \u2013 but parsing Python source code using ASTs is also a common task for linters, such as plugins for <\/span><a href=\"https:\/\/flake8.pycqa.org\/en\/latest\/\" rel=\"noopener\" ><span>flake8<\/span><\/a><span> or <\/span><a href=\"https:\/\/www.pylint.org\/\" rel=\"noopener\" ><span>pylint<\/span><\/a><span>. In the following example, <\/span><code>ast.parse()<\/code><span> is used to parse the source code <\/span><code>x = 42<\/code><span> into an <\/span><code>ast.Module<\/code><span> node, and <\/span><code>ast.dump()<\/code><span> is then used to reveal the tree-like structure of that node in a human-readable form:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">source<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"x = 42\"<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">node<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">parse<\/span><span class=\"p\">(<\/span><span class=\"n\">source<\/span><span class=\"p\">)<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">node<\/span>\n<span class=\"go\">&lt;ast.Module object at 0x000002A70F928D80&gt;<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">dump<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">indent<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">))<\/span>\n<span class=\"go\">Module(<\/span>\n<span class=\"go\">  body=[<\/span>\n<span class=\"go\">    Assign(<\/span>\n<span class=\"go\">      targets=[<\/span>\n<span class=\"go\">        Name(id='x', ctx=Store())],<\/span>\n<span class=\"go\">      value=Constant(value=42))],<\/span>\n<span class=\"go\">  type_ignores=[])<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><\/div>\n<\/div>\n<p><span>How does working with ASTs relate to pattern-matching? Well, a function to determine whether (to a reasonable approximation) an arbitrary AST node represents the symbol <\/span><code>collections.deque<\/code><span> might have looked something like this, before pattern matching\u2026<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n\n<span class=\"c1\"># This obviously won't work if the symbol is imported with an alias<\/span>\n<span class=\"c1\"># in the source code we're inspecting<\/span>\n<span class=\"c1\"># (e.g. \"from collections import deque as d\").<\/span>\n<span class=\"c1\"># But let's not worry about that here :-)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">node_represents_collections_dot_deque<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'deque' or 'collections.deque'\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"deque\"<\/span>\n    <span class=\"p\">)<\/span> <span class=\"ow\">or<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"collections\"<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"o\">.<\/span><span class=\"n\">attr<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"deque\"<\/span>\n    <span class=\"p\">)<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><\/div>\n<p><span>But in Python 3.10, pattern matching allows an elegant destructuring syntax:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">node_represents_collections_dot_deque<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'deque' or 'collections.deque'\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"deque\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"collections\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"deque\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>I know which one <\/span><em><span>I<\/span><\/em><span> prefer.<\/span><\/p>\n<p><span>For some, though, this still isn\u2019t enough \u2013 and Michael \u201cSully\u201d Sullivan is one of them. At the <a href=\"https:\/\/pyfound.blogspot.com\/2023\/05\/the-python-language-summit-2023_29.html\" rel=\"nofollow\" >Python Language Summit 2023<\/a>, Sullivan shared ideas for where pattern matching could go next.<\/span><\/p>\n<p><\/p>\n<hr \/>\n<h2 class=\"raw\"><span>Playing with matches (<\/span><a href=\"https:\/\/www.youtube.com\/watch?v=DJeMfTdvVo8\" rel=\"noopener\" ><span>without getting burned<\/span><\/a><span>)<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<p><span>Sullivan\u2019s contention is that, while pattern matching provides elegant syntactic sugar in simple cases such as the one above, our ability to chain destructurings using pattern matching is currently fairly limited. For example, say we want to write a function inspecting Python AST that takes an <\/span><code>ast.FunctionDef<\/code><span> node and identifies whether the node represents a synchronous function with exactly two parameters, both of them annotated as accepting integers. The function would behave so that the following holds true:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">source<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"def add_2(number1: int, number2: int): pass\"<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">node<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">parse<\/span><span class=\"p\">(<\/span><span class=\"n\">source<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">body<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">type<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span>\n<span class=\"go\">&lt;class 'ast.FunctionDef'&gt;<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span>\n<span class=\"go\">True<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><\/div>\n<p><span>With pre-pattern-matching syntax, we might have written such a function like this:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">def<\/span> <span class=\"nf\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span> <span class=\"o\">|<\/span> <span class=\"kc\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'int' or 'builtins.int'\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"int\"<\/span>\n    <span class=\"p\">)<\/span> <span class=\"ow\">or<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"builtins\"<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">attr<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"int\"<\/span>\n    <span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"n\">args<\/span> <span class=\"o\">=<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"ow\">and<\/span> <span class=\"nb\">all<\/span><span class=\"p\">(<\/span><span class=\"n\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">annotation<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">node<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><\/div>\n<div class=\"code\"><\/div>\n<div class=\"code\">If we wanted to rewrite this using pattern matching, we could possibly do something like this:<\/div>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">def<\/span> <span class=\"nf\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span> <span class=\"o\">|<\/span> <span class=\"kc\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'int' or 'builtins.int'\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(),<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">()]<\/span> <span class=\"k\">as<\/span> <span class=\"n\">arglist<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nb\">all<\/span><span class=\"p\">(<\/span><span class=\"n\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">arg<\/span><span class=\"o\">.<\/span><span class=\"n\">annotation<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">arg<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">arglist<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>That leaves a lot to be desired, however! The <\/span><code>is_int()<\/code><span> helper function can be rewritten in a <\/span><em><span>much<\/span><\/em><span> cleaner way. But integrating it into the <\/span><code>is_function_taking_two_ints()<\/code><span> is\u2026 somewhat icky! The code feels <\/span><em><span>harder<\/span><\/em><span> to understand than before, whereas the goal of pattern matching is to improve readability.<\/span><\/p>\n<p><span>Something like this, (ab)using metaclasses, gets us a lot closer to what it feels pattern matching <\/span><em><span>should<\/span><\/em><span> be like. By using one of Python\u2019s hooks for customising <\/span><code>isinstance()<\/code><span> logic, it\u2019s possible to rewrite our <\/span><code>is_int()<\/code><span> helper function as a class, meaning we can seamlessly integrate it into our <\/span><code>is_function_taking_two_ints()<\/code><span> function in a very expressive way:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"kn\">import<\/span> <span class=\"nn\">abc<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">PatternMeta<\/span><span class=\"p\">(<\/span><span class=\"n\">abc<\/span><span class=\"o\">.<\/span><span class=\"n\">ABCMeta<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">def<\/span> <span class=\"fm\">__instancecheck__<\/span><span class=\"p\">(<\/span><span class=\"bp\">cls<\/span><span class=\"p\">,<\/span> <span class=\"n\">inst<\/span><span class=\"p\">:<\/span> <span class=\"nb\">object<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"bp\">cls<\/span><span class=\"o\">.<\/span><span class=\"n\">match<\/span><span class=\"p\">(<\/span><span class=\"n\">inst<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">Pattern<\/span><span class=\"p\">(<\/span><span class=\"n\">metaclass<\/span><span class=\"o\">=<\/span><span class=\"n\">PatternMeta<\/span><span class=\"p\">):<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Abstract base class for types representing 'abstract patterns'\"\"\"<\/span>\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"nd\">@abc<\/span><span class=\"o\">.<\/span><span class=\"n\">abstractmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">match<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">        <\/span><span class=\"sd\">\"\"\"Subclasses must override this method\"\"\"<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"ne\">NotImplementedError<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">int_node<\/span><span class=\"p\">(<\/span><span class=\"n\">Pattern<\/span><span class=\"p\">):<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Class representing AST patterns signifying `int` or `builtins.int`\"\"\"<\/span>\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">match<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n            <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span> \n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span>\n        <span class=\"p\">]:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>This is still hardly ideal, however \u2013 that\u2019s a lot of boilerplate we\u2019ve had to introduce to our helper function for identifying <\/span><code>int<\/code><span> annotations! And who wants to muck about with metaclasses?<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<p><span><\/span><\/p>\n<table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" class=\"tr-caption-container\" style=\"margin-left: auto; margin-right: auto;\">\n<tbody>\n<tr>\n<td style=\"text-align: center;\"><a href=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjz18FEpI2W8Dx9w0LUFcj4KhCu2ml9sKxdPh33P6IBGuLx65qgBsTMJTwHPXtX7CzPYtkL81sxGJv8RJ8RQlCwKKkGy7epUxp4io7PRMeO6_ZAWF1yvlWqtg6cEiGtwhcRUl-8F7g8M3p8jwKK2b-9YHEbaacoz8OUi4LglXSPXvo3maY\" style=\"margin-left: auto; margin-right: auto;\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" data-original-height=\"607\" data-original-width=\"805\" height=\"240\" src=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjz18FEpI2W8Dx9w0LUFcj4KhCu2ml9sKxdPh33P6IBGuLx65qgBsTMJTwHPXtX7CzPYtkL81sxGJv8RJ8RQlCwKKkGy7epUxp4io7PRMeO6_ZAWF1yvlWqtg6cEiGtwhcRUl-8F7g8M3p8jwKK2b-9YHEbaacoz8OUi4LglXSPXvo3maY\" width=\"318\" \/><\/a><\/td>\n<\/tr>\n<tr>\n<td class=\"tr-caption\" style=\"text-align: center;\">A slide from Sullivan&#8217;s talk<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-size: xx-small;\"><br \/><\/span><\/p>\n<hr \/>\n<h2 class=\"raw\"><span style=\"font-size: xx-small;\"><br \/><\/span><\/h2>\n<h2 class=\"raw\"><span>A <\/span><code>__match__<\/code><span> made in heaven?<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<p><span>Sullivan proposes that we make it easier to write helper functions for pattern matching, such as the example above, without having to resort to custom metaclasses. Two competing approaches were brought for discussion.<\/span><\/p>\n<p><span>The first idea \u2013 a <\/span><code>__match__<\/code><span> special method \u2013 is perhaps the easier of the two to immediately grasp, and appeared in early drafts of the pattern matching PEPs. (It was eventually removed from the PEPs in order to reduce the scope of the proposed changes to Python.) The proposal is that any class could define a <\/span><code>__match__<\/code><span> method that could be used to customise how match statements apply to the class. Our <\/span><code>is_function_taking_two_ints()<\/code><span> case could be rewritten like so:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">class<\/span> <span class=\"nc\">int_node<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Class representing AST patterns signifying `int` or `builtins.int`\"\"\"<\/span>\n    <span class=\"c1\"># The __match__ method is understood by Python to be a static method,<\/span>\n    <span class=\"c1\"># even without the @staticmethod decorator,<\/span>\n    <span class=\"c1\"># similar to __new__ and __init_subclass__<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">__match__<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span> <span class=\"o\">|<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"c1\"># Successful matches can return custom objects,<\/span>\n                <span class=\"c1\"># that can be bound to new variables by the caller<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">node<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">node<\/span>\n            <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n                <span class=\"c1\"># Return `None` to indicate that there was no match<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">None<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span> \n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span>\n        <span class=\"p\">]:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>The second idea is more radical: the introduction of some kind of new syntax (perhaps reusing Python\u2019s <\/span><code>-&gt;<\/code><span> operator) that would allow Python coders to \u201capply\u201d functions during pattern matching. With this proposal, we could rewrite <\/span><code>is_function_taking_two_ints()<\/code><span> like so:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">def<\/span> <span class=\"nf\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span> <span class=\"o\">|<\/span> <span class=\"kc\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'int' or 'builtins.int'\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">is_int<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"kc\">True<\/span><span class=\"p\">),<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">is_int<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"kc\">True<\/span><span class=\"p\">),<\/span>\n        <span class=\"p\">]<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<style id=\"css-style\">pre { line-height: 125%; }\ntd.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\nspan.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }\ntd.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\nspan.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }\n.demo-highlight .hll { background-color: #ffffcc }\n.demo-highlight { background: #ffffff; }\n.demo-highlight .c { color: #008800; font-style: italic } \/* Comment *\/\n.demo-highlight .err { color: #a61717; background-color: #e3d2d2 } \/* Error *\/\n.demo-highlight .g { color: #2c2cff } \/* Generic *\/\n.demo-highlight .k { color: #2c2cff } \/* Keyword *\/\n.demo-highlight .x { background-color: #ffffe0 } \/* Other *\/\n.demo-highlight .ch { color: #008800; font-style: italic } \/* Comment.Hashbang *\/\n.demo-highlight .cm { color: #008800; font-style: italic } \/* Comment.Multiline *\/\n.demo-highlight .cp { color: #008800; font-style: italic } \/* Comment.Preproc *\/\n.demo-highlight .cpf { color: #008800; font-style: italic } \/* Comment.PreprocFile *\/\n.demo-highlight .c1 { color: #008800; font-style: italic } \/* Comment.Single *\/\n.demo-highlight .cs { color: #008800; font-style: italic } \/* Comment.Special *\/\n.demo-highlight .gd { color: #2c2cff } \/* Generic.Deleted *\/\n.demo-highlight .ge { color: #008800 } \/* Generic.Emph *\/\n.demo-highlight .ges { color: #2c2cff } \/* Generic.EmphStrong *\/\n.demo-highlight .gr { color: #d30202 } \/* Generic.Error *\/\n.demo-highlight .gh { color: #2c2cff } \/* Generic.Heading *\/\n.demo-highlight .gi { color: #2c2cff } \/* Generic.Inserted *\/\n.demo-highlight .go { color: #2c2cff } \/* Generic.Output *\/\n.demo-highlight .gp { color: #2c2cff } \/* Generic.Prompt *\/\n.demo-highlight .gs { color: #2c2cff } \/* Generic.Strong *\/\n.demo-highlight .gu { color: #2c2cff } \/* Generic.Subheading *\/\n.demo-highlight .gt { color: #2c2cff } \/* Generic.Traceback *\/\n.demo-highlight .kc { color: #2c2cff; font-weight: bold } \/* Keyword.Constant *\/\n.demo-highlight .kd { color: #2c2cff } \/* Keyword.Declaration *\/\n.demo-highlight .kn { color: #2c2cff } \/* Keyword.Namespace *\/\n.demo-highlight .kp { color: #2c2cff } \/* Keyword.Pseudo *\/\n.demo-highlight .kr { color: #353580; font-weight: bold } \/* Keyword.Reserved *\/\n.demo-highlight .kt { color: #2c2cff } \/* Keyword.Type *\/\n.demo-highlight .m { color: #2c8553; font-weight: bold } \/* Literal.Number *\/\n.demo-highlight .s { color: #800080 } \/* Literal.String *\/\n.demo-highlight .nb { color: #2c2cff } \/* Name.Builtin *\/\n.demo-highlight .nf { font-weight: bold; font-style: italic } \/* Name.Function *\/\n.demo-highlight .nv { color: #2c2cff; font-weight: bold } \/* Name.Variable *\/\n.demo-highlight .w { color: #bbbbbb } \/* Text.Whitespace *\/\n.demo-highlight .mb { color: #2c8553; font-weight: bold } \/* Literal.Number.Bin *\/\n.demo-highlight .mf { color: #2c8553; font-weight: bold } \/* Literal.Number.Float *\/\n.demo-highlight .mh { color: #2c8553; font-weight: bold } \/* Literal.Number.Hex *\/\n.demo-highlight .mi { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer *\/\n.demo-highlight .mo { color: #2c8553; font-weight: bold } \/* Literal.Number.Oct *\/\n.demo-highlight .sa { color: #800080 } \/* Literal.String.Affix *\/\n.demo-highlight .sb { color: #800080 } \/* Literal.String.Backtick *\/\n.demo-highlight .sc { color: #800080 } \/* Literal.String.Char *\/\n.demo-highlight .dl { color: #800080 } \/* Literal.String.Delimiter *\/\n.demo-highlight .sd { color: #800080 } \/* Literal.String.Doc *\/\n.demo-highlight .s2 { color: #800080 } \/* Literal.String.Double *\/\n.demo-highlight .se { color: #800080 } \/* Literal.String.Escape *\/\n.demo-highlight .sh { color: #800080 } \/* Literal.String.Heredoc *\/\n.demo-highlight .si { color: #800080 } \/* Literal.String.Interpol *\/\n.demo-highlight .sx { color: #800080 } \/* Literal.String.Other *\/\n.demo-highlight .sr { color: #800080 } \/* Literal.String.Regex *\/\n.demo-highlight .s1 { color: #800080 } \/* Literal.String.Single *\/\n.demo-highlight .ss { color: #800080 } \/* Literal.String.Symbol *\/\n.demo-highlight .bp { color: #2c2cff } \/* Name.Builtin.Pseudo *\/\n.demo-highlight .fm { font-weight: bold; font-style: italic } \/* Name.Function.Magic *\/\n.demo-highlight .vc { color: #2c2cff; font-weight: bold } \/* Name.Variable.Class *\/\n.demo-highlight .vg { color: #2c2cff; font-weight: bold } \/* Name.Variable.Global *\/\n.demo-highlight .vi { color: #2c2cff; font-weight: bold } \/* Name.Variable.Instance *\/\n.demo-highlight .vm { color: #2c2cff; font-weight: bold } \/* Name.Variable.Magic *\/\n.demo-highlight .il { color: #2c8553; font-weight: bold } \/* Literal.Number.Integer.Long *\/<\/style>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<div class=\"code\"><span class=\"hljs-literal\" style=\"font-size: xx-small;\"><br \/><\/span><\/div>\n<hr \/>\n<h2 class=\"raw\"><span style=\"font-size: xx-small;\"><br \/><\/span><\/h2>\n<h2 class=\"raw\"><span>Match-maker, match-maker, <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=59Hj7bp38f8\" rel=\"noopener\" ><span>make me a <\/span><code>__match__<\/code><\/a><span>\u2026<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<div><span><br \/><\/span><\/div>\n<div><span><\/p>\n<table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" class=\"tr-caption-container\" style=\"margin-left: auto; margin-right: auto;\">\n<tbody>\n<tr>\n<td style=\"text-align: center;\"><a href=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjMxObGvaIvslDc98eA-L5NJPCh56mPTurCwLIsqKxY3BHmVUaXFKcXLdFJgNMG2Ag0MxL3Q4kagE0SAAIFH-KNhuSa3k6BL0sWhn5dWK1ro1DJy7FhPwVDaZKr1o0aToh_MTmnIKy6NAFZGSSfPj1CDSBlw1tdPoUm_R-N4Z-hMnRTl4M\" style=\"margin-left: auto; margin-right: auto;\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" data-original-height=\"610\" data-original-width=\"806\" height=\"240\" src=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjMxObGvaIvslDc98eA-L5NJPCh56mPTurCwLIsqKxY3BHmVUaXFKcXLdFJgNMG2Ag0MxL3Q4kagE0SAAIFH-KNhuSa3k6BL0sWhn5dWK1ro1DJy7FhPwVDaZKr1o0aToh_MTmnIKy6NAFZGSSfPj1CDSBlw1tdPoUm_R-N4Z-hMnRTl4M\" width=\"317\" \/><\/a><\/td>\n<\/tr>\n<tr>\n<td class=\"tr-caption\" style=\"text-align: center;\">A slide from Sullivan&#8217;s talk<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/span><\/div>\n<p><span>The reception in the room to Sullivan\u2019s ideas was positive; the consensus seemed to be that there was clearly room for improvement in this area. Brandt Bucher, <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=XpxTrDDcpPE\" rel=\"noopener\" ><span>author of the original pattern matching implementation in Python 3.10<\/span><\/a><span>, concurred that this kind of enhancement was needed. \u0141ukasz Langa, meanwhile, said he\u2019d received many queries from users of other programming languages such as C#, asking how to tackle this kind of problem.<\/span><\/p>\n<p><span>The proposal for a <\/span><code>__match__<\/code><span> special method follows a pattern common in Python\u2019s data model, where double-underscore \u201cdunder\u201d methods are overridden to provide a class with special behaviour. As such, it will likely be less jarring, at first glance, to those new to the idea. Attendees of Sullivan\u2019s talk seemed, broadly, to slightly prefer the <\/span><code>__match__<\/code><span> proposal, and Sullivan himself said he thought it \u201clooked prettier\u201d.<\/span><\/p>\n<p><span>Jelle Zijlstra argued that the <\/span><code>__match__<\/code><span> dunder would provide an elegant symmetry between the construction and destruction of objects. Brandt Bucher, meanwhile, said he thought the usability improvements weren\u2019t significant enough to merit new syntax.<\/span><\/p>\n<p><span>Nonetheless, the alternative proposal for new syntax also has much to recommend it. Sullivan argued that having dedicated syntax to express the idea of \u201capplying\u201d a function during pattern matching was more explicit. Mark Shannon agreed, noting the similarity between this idea and features in the Haskell programming language. \u201cThis is functional programming,\u201d Shannon argued. \u201cIt feels weird to apply <\/span><a href=\"https:\/\/en.wikipedia.org\/wiki\/Object-oriented_programming\" rel=\"noopener\" ><span>OOP<\/span><\/a><span> models to this.\u201d<\/span><\/p>\n<p><span style=\"font-size: xx-small;\"><br \/><\/span><\/p>\n<hr \/>\n<h2 class=\"raw\"><span style=\"font-size: xx-small;\"><br \/><\/span><\/h2>\n<h2 class=\"raw\"><span>Addendum: pattern-matching resources and recipes<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<p><span>In the meantime, while we wait for a PEP, there are plenty of innovative uses of pattern matching springing up in the ecosystem. For further reading\/watching\/listening, I recommend:<\/span><\/p>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=XpxTrDDcpPE\" rel=\"noopener\" ><span>\u201cA perfect <\/span><code>match<\/code><span>: The history, design and future of Python\u2019s structural pattern matching\u201d<\/span><\/a><span> \u2013 A talk by Brandt Bucher at PyCon 2022<\/span><\/li>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=ZTvwxXL37XI\" rel=\"noopener\" ><span>\u201cStructural Pattern Matching in the Real World\u201d<\/span><\/a><span> \u2013 A talk by Raymond Hettinger at Pycon Italia 2022<\/span><\/li>\n<li><a href=\"https:\/\/github.com\/nedbat\/adventofcode2022\/blob\/main\/day07.py\" rel=\"noopener\" ><code>RegexMatcher<\/code><\/a><span>: a class integrating pattern matching with Python\u2019s <\/span><code>re<\/code><span> module. A 2022 Advent of Code solution by Ned Batchelder.<\/span><\/li>\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/72596436\/how-to-perform-approximate-structural-pattern-matching-for-floats-and-complex\" rel=\"noopener\" ><code>approximately<\/code><\/a><span>: A way to compare <\/span><code>float<\/code><span> and <\/span><code>complex<\/code><span> numbers using pattern matching, while avoiding the <\/span><a href=\"https:\/\/docs.python.org\/3\/tutorial\/floatingpoint.html\" rel=\"noopener\" ><span>perils of floating-point arithmetic<\/span><\/a><span>. A StackOverflow Q&amp;A by Raymond Hettinger.<\/span><\/li>\n<li><a href=\"https:\/\/gist.github.com\/msullivan\/7f533f927a4ba3fffd856cb0c9527106\" rel=\"noopener\" ><span>\u201cA few related schemes for implementing view patterns in Python\u201d<\/span><\/a><span>: A gist by Michael Sullivan (from February 2023)<\/span><\/li>\n<\/ul>\n\n<p class=\"syndicated-attribution\"><figure class= \\\"wp-block-image alignnone \\\"><img src= \\\"http:\/\/itteacheritfreelance.hk\/test\/wordpress\/wp-content\/uploads\/2016\/05\/logo2-2.png\\\" alt=\\\"IT\u96fb\u8166\u88dc\u7fd2 java\u88dc\u7fd2 \u70ba\u5927\u5bb6\u914d\u5c0d\u96fb\u8166\u88dc\u7fd2,IT freelance, \u79c1\u4eba\u8001\u5e2b, PHP\u88dc\u7fd2,CSS\u88dc\u7fd2,XML,Java\u88dc\u7fd2,MySQL\u88dc\u7fd2,graphic design\u88dc\u7fd2,\u4e2d\u5c0f\u5b78ICT\u88dc\u7fd2,\u4e00\u5c0d\u4e00\u79c1\u4eba\u88dc\u7fd2\u548cFreelance\u81ea\u7531\u5de5\u4f5c\u914d\u5c0d\u3002\\\"\/><figcaption>\u7acb\u523b\u8a3b\u518a\u53ca\u5831\u540d\u96fb\u8166\u88dc\u7fd2\u8ab2\u7a0b\u5427!<\/figcaption><\/figure>\r\n<\/br>Find A Teacher Form:\r\n<\/br>https:\/\/docs.google.com\/forms\/d\/1vREBnX5n262umf4wU5U2pyTwvk9O-JrAgblA-wH9GFQ\/viewform?edit_requested=true#responses\r\n<\/br><\/br>Email:\r\n<\/br>public1989two@gmail.com<br><br><br><br><br><br><br>\r\n<a href=www.itsec.hk style=color:#FFFFFF;>www.itsec.hk<\/a><br>\r\n<a href=\\\"www.itsec.vip\\\" style=color:#FFFFFF;>www.itsec.vip<\/a><br>\r\n<a href=\\\"www.itseceu.uk\\\" style=color:#FFFFFF;>www.itseceu.uk<\/a><br><\/p>","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><div class=\"markdown-body container-fluid comment-inner comment-enabled\" data-hard-breaks=\"true\">One of the most exciting new features in Python 3.10 was <a href=\"https:\/\/docs.python.org\/3\/whatsnew\/3.10.html#pep-634-structural-pattern-matching\">the introduction of pattern matching<\/a> (introduced in PEPs <a href=\"https:\/\/peps.python.org\/pep-0634\/\">634<\/a>, <a href=\"https:\/\/peps.python.org\/pep-0635\/\">635<\/a> and <a href=\"https:\/\/peps.python.org\/pep-0636\/\">636<\/a>). Pattern matching has a wide variety of uses, but really shines in situations where you need to undergo complex destructurings of tree-like datastructures.<\/p>\n<p><span>That\u2019s a lot of words which may or may not mean very much to you \u2013 but consider, for example, using <\/span><a href=\"https:\/\/docs.python.org\/3\/library\/ast.html\" rel=\"noopener\" target=\"_blank\"><span>the <\/span><code>ast<\/code><span> module<\/span><\/a><span> to parse Python source code. If you\u2019re unfamiliar with the <\/span><code>ast<\/code><span> module: the module provides tools that enable you to compile Python source code into an \u201cabstract syntax tree\u201d (AST) representing the code\u2019s structure. The Python interpreter itself converts Python source code into an AST in order to understand how to run that code \u2013 but parsing Python source code using ASTs is also a common task for linters, such as plugins for <\/span><a href=\"https:\/\/flake8.pycqa.org\/en\/latest\/\" rel=\"noopener\" target=\"_blank\"><span>flake8<\/span><\/a><span> or <\/span><a href=\"https:\/\/www.pylint.org\/\" rel=\"noopener\" target=\"_blank\"><span>pylint<\/span><\/a><span>. In the following example, <\/span><code>ast.parse()<\/code><span> is used to parse the source code <\/span><code>x = 42<\/code><span> into an <\/span><code>ast.Module<\/code><span> node, and <\/span><code>ast.dump()<\/code><span> is then used to reveal the tree-like structure of that node in a human-readable form:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">source<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"x = 42\"<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">node<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">parse<\/span><span class=\"p\">(<\/span><span class=\"n\">source<\/span><span class=\"p\">)<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">node<\/span>\n<span class=\"go\">&lt;ast.Module object at 0x000002A70F928D80&gt;<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">print<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">dump<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">indent<\/span><span class=\"o\">=<\/span><span class=\"mi\">2<\/span><span class=\"p\">))<\/span>\n<span class=\"go\">Module(<\/span>\n<span class=\"go\">  body=[<\/span>\n<span class=\"go\">    Assign(<\/span>\n<span class=\"go\">      targets=[<\/span>\n<span class=\"go\">        Name(id='x', ctx=Store())],<\/span>\n<span class=\"go\">      value=Constant(value=42))],<\/span>\n<span class=\"go\">  type_ignores=[])<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><\/div>\n<\/div>\n<p><span>How does working with ASTs relate to pattern-matching? Well, a function to determine whether (to a reasonable approximation) an arbitrary AST node represents the symbol <\/span><code>collections.deque<\/code><span> might have looked something like this, before pattern matching\u2026<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n\n<span class=\"c1\"># This obviously won't work if the symbol is imported with an alias<\/span>\n<span class=\"c1\"># in the source code we're inspecting<\/span>\n<span class=\"c1\"># (e.g. \"from collections import deque as d\").<\/span>\n<span class=\"c1\"># But let's not worry about that here :-)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">node_represents_collections_dot_deque<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'deque' or 'collections.deque'\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"deque\"<\/span>\n    <span class=\"p\">)<\/span> <span class=\"ow\">or<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"collections\"<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"o\">.<\/span><span class=\"n\">attr<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"deque\"<\/span>\n    <span class=\"p\">)<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><\/div>\n<p><span>But in Python 3.10, pattern matching allows an elegant destructuring syntax:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">node_represents_collections_dot_deque<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'deque' or 'collections.deque'\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"deque\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"collections\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"deque\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>I know which one <\/span><em><span>I<\/span><\/em><span> prefer.<\/span><\/p>\n<p><span>For some, though, this still isn\u2019t enough \u2013 and Michael \u201cSully\u201d Sullivan is one of them. At the <a href=\"https:\/\/pyfound.blogspot.com\/2023\/05\/the-python-language-summit-2023_29.html\" rel=\"nofollow noopener\" target=\"\">Python Language Summit 2023<\/a>, Sullivan shared ideas for where pattern matching could go next.<\/span><\/p>\n<p><\/p>\n<hr>\n<h2 class=\"raw\"><span>Playing with matches (<\/span><a href=\"https:\/\/www.youtube.com\/watch?v=DJeMfTdvVo8\" rel=\"noopener\" target=\"_blank\"><span>without getting burned<\/span><\/a><span>)<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<p><span>Sullivan\u2019s contention is that, while pattern matching provides elegant syntactic sugar in simple cases such as the one above, our ability to chain destructurings using pattern matching is currently fairly limited. For example, say we want to write a function inspecting Python AST that takes an <\/span><code>ast.FunctionDef<\/code><span> node and identifies whether the node represents a synchronous function with exactly two parameters, both of them annotated as accepting integers. The function would behave so that the following holds true:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">source<\/span> <span class=\"o\">=<\/span> <span class=\"s2\">\"def add_2(number1: int, number2: int): pass\"<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">node<\/span> <span class=\"o\">=<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">parse<\/span><span class=\"p\">(<\/span><span class=\"n\">source<\/span><span class=\"p\">)<\/span><span class=\"o\">.<\/span><span class=\"n\">body<\/span><span class=\"p\">[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"nb\">type<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span>\n<span class=\"go\">&lt;class 'ast.FunctionDef'&gt;<\/span>\n<span class=\"gp\">&gt;&gt;&gt; <\/span><span class=\"n\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span>\n<span class=\"go\">True<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><\/div>\n<p><span>With pre-pattern-matching syntax, we might have written such a function like this:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">def<\/span> <span class=\"nf\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span> <span class=\"o\">|<\/span> <span class=\"kc\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'int' or 'builtins.int'\"\"\"<\/span>\n    <span class=\"k\">return<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span> <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"int\"<\/span>\n    <span class=\"p\">)<\/span> <span class=\"ow\">or<\/span> <span class=\"p\">(<\/span>\n        <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"nb\">isinstance<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"p\">,<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">)<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">value<\/span><span class=\"o\">.<\/span><span class=\"n\">id<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"builtins\"<\/span>\n        <span class=\"ow\">and<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">attr<\/span> <span class=\"o\">==<\/span> <span class=\"s2\">\"int\"<\/span>\n    <span class=\"p\">)<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"n\">args<\/span> <span class=\"o\">=<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nb\">len<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span> <span class=\"o\">==<\/span> <span class=\"mi\">2<\/span> <span class=\"ow\">and<\/span> <span class=\"nb\">all<\/span><span class=\"p\">(<\/span><span class=\"n\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">annotation<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">node<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><\/div>\n<div class=\"code\"><\/div>\n<div class=\"code\">If we wanted to rewrite this using pattern matching, we could possibly do something like this:<\/div>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">def<\/span> <span class=\"nf\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span> <span class=\"o\">|<\/span> <span class=\"kc\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'int' or 'builtins.int'\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(),<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">()]<\/span> <span class=\"k\">as<\/span> <span class=\"n\">arglist<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"nb\">all<\/span><span class=\"p\">(<\/span><span class=\"n\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">arg<\/span><span class=\"o\">.<\/span><span class=\"n\">annotation<\/span><span class=\"p\">)<\/span> <span class=\"k\">for<\/span> <span class=\"n\">arg<\/span> <span class=\"ow\">in<\/span> <span class=\"n\">arglist<\/span><span class=\"p\">)<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>That leaves a lot to be desired, however! The <\/span><code>is_int()<\/code><span> helper function can be rewritten in a <\/span><em><span>much<\/span><\/em><span> cleaner way. But integrating it into the <\/span><code>is_function_taking_two_ints()<\/code><span> is\u2026 somewhat icky! The code feels <\/span><em><span>harder<\/span><\/em><span> to understand than before, whereas the goal of pattern matching is to improve readability.<\/span><\/p>\n<p><span>Something like this, (ab)using metaclasses, gets us a lot closer to what it feels pattern matching <\/span><em><span>should<\/span><\/em><span> be like. By using one of Python\u2019s hooks for customising <\/span><code>isinstance()<\/code><span> logic, it\u2019s possible to rewrite our <\/span><code>is_int()<\/code><span> helper function as a class, meaning we can seamlessly integrate it into our <\/span><code>is_function_taking_two_ints()<\/code><span> function in a very expressive way:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"kn\">import<\/span> <span class=\"nn\">abc<\/span>\n<span class=\"kn\">import<\/span> <span class=\"nn\">ast<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">PatternMeta<\/span><span class=\"p\">(<\/span><span class=\"n\">abc<\/span><span class=\"o\">.<\/span><span class=\"n\">ABCMeta<\/span><span class=\"p\">):<\/span>\n    <span class=\"k\">def<\/span> <span class=\"fm\">__instancecheck__<\/span><span class=\"p\">(<\/span><span class=\"bp\">cls<\/span><span class=\"p\">,<\/span> <span class=\"n\">inst<\/span><span class=\"p\">:<\/span> <span class=\"nb\">object<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">return<\/span> <span class=\"bp\">cls<\/span><span class=\"o\">.<\/span><span class=\"n\">match<\/span><span class=\"p\">(<\/span><span class=\"n\">inst<\/span><span class=\"p\">)<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">Pattern<\/span><span class=\"p\">(<\/span><span class=\"n\">metaclass<\/span><span class=\"o\">=<\/span><span class=\"n\">PatternMeta<\/span><span class=\"p\">):<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Abstract base class for types representing 'abstract patterns'\"\"\"<\/span>\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"nd\">@abc<\/span><span class=\"o\">.<\/span><span class=\"n\">abstractmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">match<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">        <\/span><span class=\"sd\">\"\"\"Subclasses must override this method\"\"\"<\/span>\n        <span class=\"k\">raise<\/span> <span class=\"ne\">NotImplementedError<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">int_node<\/span><span class=\"p\">(<\/span><span class=\"n\">Pattern<\/span><span class=\"p\">):<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Class representing AST patterns signifying `int` or `builtins.int`\"\"\"<\/span>\n    <span class=\"nd\">@staticmethod<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">match<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n            <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span> \n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span>\n        <span class=\"p\">]:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>This is still hardly ideal, however \u2013 that\u2019s a lot of boilerplate we\u2019ve had to introduce to our helper function for identifying <\/span><code>int<\/code><span> annotations! And who wants to muck about with metaclasses?<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<p><span><\/span><\/p>\n<table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" class=\"tr-caption-container\">\n<tbody>\n<tr>\n<td><a href=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjz18FEpI2W8Dx9w0LUFcj4KhCu2ml9sKxdPh33P6IBGuLx65qgBsTMJTwHPXtX7CzPYtkL81sxGJv8RJ8RQlCwKKkGy7epUxp4io7PRMeO6_ZAWF1yvlWqtg6cEiGtwhcRUl-8F7g8M3p8jwKK2b-9YHEbaacoz8OUi4LglXSPXvo3maY\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" data-original-height=\"607\" data-original-width=\"805\" height=\"240\" src=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjz18FEpI2W8Dx9w0LUFcj4KhCu2ml9sKxdPh33P6IBGuLx65qgBsTMJTwHPXtX7CzPYtkL81sxGJv8RJ8RQlCwKKkGy7epUxp4io7PRMeO6_ZAWF1yvlWqtg6cEiGtwhcRUl-8F7g8M3p8jwKK2b-9YHEbaacoz8OUi4LglXSPXvo3maY\" width=\"318\"><\/a><\/td>\n<\/tr>\n<tr>\n<td class=\"tr-caption\">A slide from Sullivan&#8217;s talk<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span><br \/><\/span><\/p>\n<hr>\n<h2 class=\"raw\"><span><br \/><\/span><\/h2>\n<h2 class=\"raw\"><span>A <\/span><code>__match__<\/code><span> made in heaven?<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<p><span>Sullivan proposes that we make it easier to write helper functions for pattern matching, such as the example above, without having to resort to custom metaclasses. Two competing approaches were brought for discussion.<\/span><\/p>\n<p><span>The first idea \u2013 a <\/span><code>__match__<\/code><span> special method \u2013 is perhaps the easier of the two to immediately grasp, and appeared in early drafts of the pattern matching PEPs. (It was eventually removed from the PEPs in order to reduce the scope of the proposed changes to Python.) The proposal is that any class could define a <\/span><code>__match__<\/code><span> method that could be used to customise how match statements apply to the class. Our <\/span><code>is_function_taking_two_ints()<\/code><span> case could be rewritten like so:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">class<\/span> <span class=\"nc\">int_node<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Class representing AST patterns signifying `int` or `builtins.int`\"\"\"<\/span>\n    <span class=\"c1\"># The __match__ method is understood by Python to be a static method,<\/span>\n    <span class=\"c1\"># even without the @staticmethod decorator,<\/span>\n    <span class=\"c1\"># similar to __new__ and __init_subclass__<\/span>\n    <span class=\"k\">def<\/span> <span class=\"nf\">__match__<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span> <span class=\"o\">|<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"c1\"># Successful matches can return custom objects,<\/span>\n                <span class=\"c1\"># that can be bound to new variables by the caller<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">node<\/span>\n            <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n                <span class=\"k\">return<\/span> <span class=\"n\">node<\/span>\n            <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n                <span class=\"c1\"># Return `None` to indicate that there was no match<\/span>\n                <span class=\"k\">return<\/span> <span class=\"kc\">None<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span> \n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">int_node<\/span><span class=\"p\">()),<\/span>\n        <span class=\"p\">]:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<p><span>The second idea is more radical: the introduction of some kind of new syntax (perhaps reusing Python\u2019s <\/span><code>-&gt;<\/code><span> operator) that would allow Python coders to \u201capply\u201d functions during pattern matching. With this proposal, we could rewrite <\/span><code>is_function_taking_two_ints()<\/code><span> like so:<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<div class=\"demo-highlight\">\n<pre><span><\/span><span class=\"k\">def<\/span> <span class=\"nf\">is_int<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">AST<\/span> <span class=\"o\">|<\/span> <span class=\"kc\">None<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents 'int' or 'builtins.int'\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Attribute<\/span><span class=\"p\">(<\/span><span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">Name<\/span><span class=\"p\">(<\/span><span class=\"s2\">\"builtins\"<\/span><span class=\"p\">),<\/span> <span class=\"s2\">\"int\"<\/span><span class=\"p\">):<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">True<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n\n<span class=\"k\">def<\/span> <span class=\"nf\">is_function_taking_two_ints<\/span><span class=\"p\">(<\/span><span class=\"n\">node<\/span><span class=\"p\">:<\/span> <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">FunctionDef<\/span><span class=\"p\">)<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"nb\">bool<\/span><span class=\"p\">:<\/span>\n<span class=\"w\">    <\/span><span class=\"sd\">\"\"\"Determine if *node* represents a function that accepts two ints\"\"\"<\/span>\n    <span class=\"k\">match<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">posonlyargs<\/span> <span class=\"o\">+<\/span> <span class=\"n\">node<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"o\">.<\/span><span class=\"n\">args<\/span><span class=\"p\">:<\/span>\n        <span class=\"k\">case<\/span> <span class=\"p\">[<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">is_int<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"kc\">True<\/span><span class=\"p\">),<\/span>\n            <span class=\"n\">ast<\/span><span class=\"o\">.<\/span><span class=\"n\">arg<\/span><span class=\"p\">(<\/span><span class=\"n\">annotation<\/span><span class=\"o\">=<\/span><span class=\"n\">is_int<\/span> <span class=\"o\">-&gt;<\/span> <span class=\"kc\">True<\/span><span class=\"p\">),<\/span>\n        <span class=\"p\">]<\/span>\n        <span class=\"k\">case<\/span><span class=\"w\"> <\/span><span class=\"k\">_<\/span><span class=\"p\">:<\/span>\n            <span class=\"k\">return<\/span> <span class=\"kc\">False<\/span>\n<\/pre>\n<\/div>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<div class=\"code\"><span class=\"hljs-literal\"><br \/><\/span><\/div>\n<hr>\n<h2 class=\"raw\"><span><br \/><\/span><\/h2>\n<h2 class=\"raw\"><span>Match-maker, match-maker, <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=59Hj7bp38f8\" rel=\"noopener\" target=\"_blank\"><span>make me a <\/span><code>__match__<\/code><\/a><span>\u2026<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<div><span><br \/><\/span><\/div>\n<div><span><\/p>\n<table align=\"center\" cellpadding=\"0\" cellspacing=\"0\" class=\"tr-caption-container\">\n<tbody>\n<tr>\n<td><a href=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjMxObGvaIvslDc98eA-L5NJPCh56mPTurCwLIsqKxY3BHmVUaXFKcXLdFJgNMG2Ag0MxL3Q4kagE0SAAIFH-KNhuSa3k6BL0sWhn5dWK1ro1DJy7FhPwVDaZKr1o0aToh_MTmnIKy6NAFZGSSfPj1CDSBlw1tdPoUm_R-N4Z-hMnRTl4M\"><img loading=\"lazy\" decoding=\"async\" alt=\"\" data-original-height=\"610\" data-original-width=\"806\" height=\"240\" src=\"https:\/\/blogger.googleusercontent.com\/img\/a\/AVvXsEjMxObGvaIvslDc98eA-L5NJPCh56mPTurCwLIsqKxY3BHmVUaXFKcXLdFJgNMG2Ag0MxL3Q4kagE0SAAIFH-KNhuSa3k6BL0sWhn5dWK1ro1DJy7FhPwVDaZKr1o0aToh_MTmnIKy6NAFZGSSfPj1CDSBlw1tdPoUm_R-N4Z-hMnRTl4M\" width=\"317\"><\/a><\/td>\n<\/tr>\n<tr>\n<td class=\"tr-caption\">A slide from Sullivan&#8217;s talk<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><\/span><\/div>\n<p><span>The reception in the room to Sullivan\u2019s ideas was positive; the consensus seemed to be that there was clearly room for improvement in this area. Brandt Bucher, <\/span><a href=\"https:\/\/www.youtube.com\/watch?v=XpxTrDDcpPE\" rel=\"noopener\" target=\"_blank\"><span>author of the original pattern matching implementation in Python 3.10<\/span><\/a><span>, concurred that this kind of enhancement was needed. \u0141ukasz Langa, meanwhile, said he\u2019d received many queries from users of other programming languages such as C#, asking how to tackle this kind of problem.<\/span><\/p>\n<p><span>The proposal for a <\/span><code>__match__<\/code><span> special method follows a pattern common in Python\u2019s data model, where double-underscore \u201cdunder\u201d methods are overridden to provide a class with special behaviour. As such, it will likely be less jarring, at first glance, to those new to the idea. Attendees of Sullivan\u2019s talk seemed, broadly, to slightly prefer the <\/span><code>__match__<\/code><span> proposal, and Sullivan himself said he thought it \u201clooked prettier\u201d.<\/span><\/p>\n<p><span>Jelle Zijlstra argued that the <\/span><code>__match__<\/code><span> dunder would provide an elegant symmetry between the construction and destruction of objects. Brandt Bucher, meanwhile, said he thought the usability improvements weren\u2019t significant enough to merit new syntax.<\/span><\/p>\n<p><span>Nonetheless, the alternative proposal for new syntax also has much to recommend it. Sullivan argued that having dedicated syntax to express the idea of \u201capplying\u201d a function during pattern matching was more explicit. Mark Shannon agreed, noting the similarity between this idea and features in the Haskell programming language. \u201cThis is functional programming,\u201d Shannon argued. \u201cIt feels weird to apply <\/span><a href=\"https:\/\/en.wikipedia.org\/wiki\/Object-oriented_programming\" rel=\"noopener\" target=\"_blank\"><span>OOP<\/span><\/a><span> models to this.\u201d<\/span><\/p>\n<p><span><br \/><\/span><\/p>\n<hr>\n<h2 class=\"raw\"><span><br \/><\/span><\/h2>\n<h2 class=\"raw\"><span>Addendum: pattern-matching resources and recipes<\/span><\/h2>\n<div><span><br \/><\/span><\/div>\n<p><span>In the meantime, while we wait for a PEP, there are plenty of innovative uses of pattern matching springing up in the ecosystem. For further reading\/watching\/listening, I recommend:<\/span><\/p>\n<ul>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=XpxTrDDcpPE\" rel=\"noopener\" target=\"_blank\"><span>\u201cA perfect <\/span><code>match<\/code><span>: The history, design and future of Python\u2019s structural pattern matching\u201d<\/span><\/a><span> \u2013 A talk by Brandt Bucher at PyCon 2022<\/span><\/li>\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=ZTvwxXL37XI\" rel=\"noopener\" target=\"_blank\"><span>\u201cStructural Pattern Matching in the Real World\u201d<\/span><\/a><span> \u2013 A talk by Raymond Hettinger at Pycon Italia 2022<\/span><\/li>\n<li><a href=\"https:\/\/github.com\/nedbat\/adventofcode2022\/blob\/main\/day07.py\" rel=\"noopener\" target=\"_blank\"><code>RegexMatcher<\/code><\/a><span>: a class integrating pattern matching with Python\u2019s <\/span><code>re<\/code><span> module. A 2022 Advent of Code solution by Ned Batchelder.<\/span><\/li>\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/72596436\/how-to-perform-approximate-structural-pattern-matching-for-floats-and-complex\" rel=\"noopener\" target=\"_blank\"><code>approximately<\/code><\/a><span>: A way to compare <\/span><code>float<\/code><span> and <\/span><code>complex<\/code><span> numbers using pattern matching, while avoiding the <\/span><a href=\"https:\/\/docs.python.org\/3\/tutorial\/floatingpoint.html\" rel=\"noopener\" target=\"_blank\"><span>perils of floating-point arithmetic<\/span><\/a><span>. A StackOverflow Q&amp;A by Raymond Hettinger.<\/span><\/li>\n<li><a href=\"https:\/\/gist.github.com\/msullivan\/7f533f927a4ba3fffd856cb0c9527106\" rel=\"noopener\" target=\"_blank\"><span>\u201cA few related schemes for implementing view patterns in Python\u201d<\/span><\/a><span>: A gist by Michael Sullivan (from February 2023)<\/span><\/li>\n<\/ul>\n<\/div>","protected":false},"author":2053,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"slim_seo":{"title":"The Python Language Summit 2023: Pattern Matching, __match__, and View Patterns - ITTeacherITFreelance.hk","description":"One of the most exciting new features in Python 3.10 was the introduction of pattern matching (introduced in PEPs 634 , 635 and 636 ). Pattern matching has a wi"},"footnotes":""},"categories":[10700],"tags":[],"_links":{"self":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329466"}],"collection":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/2053"}],"replies":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=329466"}],"version-history":[{"count":1,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329466\/revisions"}],"predecessor-version":[{"id":329467,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329466\/revisions\/329467"}],"wp:attachment":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=329466"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=329466"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=329466"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}