PEP 642 v3: Explicit Pattern Syntax for Structural Pattern Matching

I’ve made a final round of updates to PEP 642 and submitted it to the Steering Council for consideration alongside PEP 634.

As usual, the rendered version can be found here: PEP 642 -- Explicit Pattern Syntax for Structural Pattern Matching | Python.org

There are some pretty significant changes relative to v2, although I did already discuss most of them in the v2 thread at PEP 642: Constraint Pattern Syntax for Structural Pattern Matching

The PEP itself contains a list of major changes relative to PEP 634, so I won’t repeat that here.

Instead I’ll summarise the parts that I consider most important:

  • ensuring that all “binding to the right” operations use the as keyword. This drove changes to both mapping patterns and class patterns.
  • explicitly qualifying both name bindings and value constraints with as , == , or is . This change makes it possible to make pattern matching available to users without having to resolve the thorny questions of what bare names and attribute references should do by default. It also opens up the possibility of potentially adding more value constraint options later (like in , is not , and != ) if those operations seem sufficiently compelling to be worth adding.
  • explicitly decoupling sequence pattern matching from iterable unpacking. The change to require qualification of name binding operations already breaks the alignment between the two, and that created an opportunity to simplify the grammar by only allowing square bracket based sequence patterns and eliminating both open sequence patterns and parenthesis based sequence patterns
  • changing class patterns to draw more of their syntactic inspiration from mapping patterns rather than from class instantiation
  • explicitly representing patterns in the AST, rather than treating patterns as pseudo-expressions all the way through to the code generation layer. Skipping this step makes the code fragile and hard to follow, as there isn’t actually any point in the AST that accepts both expressions and patterns, but with pattern parsing reusing expression nodes, you can’t tell from just looking at the AST which nodes expect subexpressions and which expect subpatterns.

I’ll also quote the example match statement from the PEP abstract, which extracts “host” and “port” details from a 2 item sequence, a mapping with “host” and “port” keys, any object with “host” and “port” attributes, or a “host:port” string, treating the “port” as optional in the latter three cases:

    port = DEFAULT_PORT
    match expr:
        case [as host, as port]:
            pass
        case {"host" as host, "port" as port}:
            pass
        case {"host" as host}:
            pass
        case object{.host as host, .port as port}:
            pass
        case object{.host as host}:
            pass
        case str{} as addr:
            host, __, optional_port = addr.partition(":")
            if optional_port:
                port = optional_port
        case __ as m:
            raise TypeError(f"Unknown address format: {m!r:.200}")
    port = int(port)
2 Likes

I don’t have particularly strong opinions on this, but I had an idea that I thought I’d put out there:

If this feature isn’t approved as part of the language, perhaps it could be incorporated as a macro in the stdlib if that PEP is approved.

Aye, offering an alternative to native pattern matching support was part of the motivation for that PEP being submitted.