PEP 845: Leading-Dot Value Patterns

For your consideration: PEP 845, with the following abstract:

This PEP enables the use of non-attribute names as value patterns in match statements. A name prefixed with a dot is looked up using the normal name resolution rules and compared to the match subject by equality in the same manner as existing value patterns, instead of being treated as a capture pattern. This makes it possible to match local variables and global variables defined in the same module without using a guard clause.

def get_book_titles_for_author(author: str):
    for book in BOOKS:
        match book:
            case {"title": title, "author": .author}:
                yield title

You can also try it out in the demo here: https://pep845-demo.pages.dev/

35 Likes

Cool idea! Is Literal[author] possible? Or does that violate Literal’s normal usage too much? Feel free to add it to rejected ideas.

Not exactly sure what you’re referring to. Would you mind posting a small example? That might help me better understand what you’re getting at. Feel free to also try out the online demo linked above.

I just mean instead of .author as syntax.

I don’t think that will work. The match statement mini-syntax doesn’t support [ ]. Even ( ) isn’t recognized as a function call but an isinstance check instead. So we’d first have to define what [ ] means for pattern matching.

2 Likes

Very cool, I really like the intuitive syntax choice!

I don’t think the following is specified: can .NAME resolve to an identifier captured earlier in the same pattern?

match seq:
    case [x, *_, .x]:  # first and last elements are equal
        ...    

If so, it would also raise the question of precedence in case of a conflict.

c.f. Elixir’s pin (^) operator is strictly for existing bindings, though it also supports non-linear matching via repetition.

6 Likes

This looks like a good solution to this problem. I have had to work around this issue, in one case introducing a wrapping object just so that I could match it with box.value.

+1 from me on this idea.

I don’t know how intuitive this syntax is for me. It kinda looks like you try to match an object that has an author attribute. (Like some sort of an inline Protocol).

4 Likes

That’s not possible. Name captures are only assigned after the pattern itself matched (but before the guard is evaluated). Therefore your example would raise an error.

>>> match [1, 1]:
...     case [x, *_, .x]:
...        pass
...        
Traceback (most recent call last):
  File "<python-input-8>", line 2, in <module>
    case [x, *_, .x]:
                  ^
NameError: name 'x' is not defined
2 Likes

I wish I had something more interesting to contribute other than I’m very much in favor of this, and see little downside!

3 Likes