DRMacIver's Notebook

Python has structural pattern matching

Python has structural pattern matching

Hey, did you know that this works?


>>> from dataclasses import dataclass
>>> @dataclass
... class Foo:
...     x: int
...
>>> @dataclass
... class Bar:
...     x: str
...
>>> match Foo(x=1):
...     case object(x=x):
...         print(x)
...
1
>>> match Bar(x=1):
...     case object(x=2):
...         print(x)
...
>>> match Bar(x=1):
...     case object(x=x):
...         print(x)
...
1
>>> match Bar(x=1):
...     case object(x=2):
...         print(x)
...     case object(x=1):
...         print("hello!")
...
hello!

You can use “object” as a matcher to match based solely on whether a value being passed in has a particular field, and you can descend into the value of those fields with other match expressions as you like.

Python’s pattern matching is a bit of a weird beast because those things in a case expression that look like constructor parameters are nothing of the sort, they’re just fields, and they don’t have any relationship to the type you’re matching on, they’ll just bind to the field of that name on the object being matched and the match will fail if the field is not present. The type you’re matching on is just an instanceof checkAnd, of course, that instanceof check doesn’t have to be a real instanceof check and can use ABC subclass nonsense and doesn’t have anything to do with the fields.

As a result, you can use an object match (or any other type you want to match on) with arbitrary fields, and the match expression will check for the presence of the field.

In some sense this is how it has to work but it was non-obvious to me that it would work. In particular I thought there was a decent chance that this would raise an AttributeError if you tried to match on a missing field, but instead it handles that and you get arbitrary structural pattern matching on record types if you want it.

I can’t decide if this is cool or gross or both. More importantly, I can’t actually think of a case where I’d actually need to use this feature. I think it definitely straddles the line between “weird hack” and “genuinely interesting language feature”, but because we’ve mostly moved away from duck typing in Python, and because most of my usage of pattern matching is effectively with closed algebraic data types, I can’t actually immediately think of many places I’d want to use it.