Python Pattern Matching
Composable patterns and regular expressions for Python objects.
Python Pattern Matching is a small, pure-Python library for matching values, destructuring sequences, binding names, applying predicates, and expressing regular-expression-style patterns over sequences of arbitrary Python objects.
Patterns are ordinary runtime values. There are no import hooks, codecs, AST transforms, or special syntax.
pip install patternmatching
Sixty-second tour
Match literals, types, nested sequences, and predicates:
from patternmatching import bind, bound, like, match
message = ["created", "/users/42", 201]
assert match(
message,
[
"created",
bind.path,
like(lambda status: 200 <= status < 300, name=None),
],
)
assert bound.path == "/users/42"
A type used as a pattern matches its instances. A like(...) pattern applies
a callable, or a text regular expression, to the value.
Bindings are also equality constraints when reused:
assert match(("left", "left"), (bind.side, bind.side))
assert bound.side == "left"
assert not match(("left", "right"), (bind.side, bind.side))
Regular expressions for object sequences
The same object patterns compose into regex-like sequence patterns. Repetition, alternatives, exclusion, capturing groups, greediness, and backtracking work on strings, lists, tuples, and other indexable sequences.
from patternmatching import bound, group, match, padding, repeat
events = ["noise", "BEGIN", 1, 2, 3, "END", "tail"]
pattern = (
padding
+ ["BEGIN"]
+ (int * repeat(min=1)) * group("values")
+ ["END"]
)
assert match(events, pattern)
assert bound.values == [1, 2, 3]
Here padding is a non-greedy repetition of any object. The int pattern
matches integer objects, repeat(min=1) requires one or more, and group(...)
captures the matching slice.
Sequence patterns match from the beginning and may match a prefix, like
re.match. A successful pattern does not inherently require consuming the
entire sequence.
Pattern vocabulary
Literals and equality
Literal patterns compare equal to the value:
assert match(1, 1)
assert match("hello", "hello")
Other objects also match by equality when no more specific rule applies.
Types
A class pattern uses isinstance. When the value is itself a class,
issubclass is used:
assert match(42, int)
assert match(bool, int)
Sequences
Lists match list patterns, tuples match tuple patterns, and nested patterns are visited recursively:
assert match([1, "two", [3.0]], [int, str, [float]])
Bindings
Any attribute of bind creates a named binding pattern. bind.any matches one
value without storing it:
assert match([1, 2, 3], [bind.any, bind.middle, bind.any])
assert bound.middle == 2
Each successful call pushes its bindings onto bound. Attribute and mapping
access read the most recent result. bound.pop() discards it and
bound.reset() clears all results. bound.reset can also decorate a function
to scope the results it creates.
Predicates and text regular expressions
like(pattern, name="match") applies a callable to the value. A falsy result,
or a common value/lookup/type error, is a mismatch. A truthy result is bound
under name; pass name=None when no result is needed.
When pattern is text, it is passed to re.match:
assert match("item-42", like(r"item-(\d+)"))
assert bound.match.group(1) == "42"
Custom patterns
Pattern objects can implement __match__(matcher, value). Raise
patternmatching.Mismatch to reject the value, or return normally to accept it:
import patternmatching
class Between:
def __init__(self, low, high):
self.low = low
self.high = high
def __match__(self, matcher, value):
if not self.low <= value <= self.high:
raise patternmatching.Mismatch
assert patternmatching.match(7, Between(1, 10))
The Matcher class also accepts an ordered collection of matching cases for
applications that need to define an entire matching vocabulary.
Sequence pattern operators
anyonematches one object.anythingmatches zero or more objects greedily.somethingmatches one or more objects greedily.paddingmatches zero or more objects non-greedily.pattern * repeat(min=0, max=inf, greedy=True)repeats a pattern.pattern * maybematches zero or one occurrence.either(a, b, ...)matches the first successful alternative.exclude(a, b, ...)consumes one object if none of its alternatives match.pattern * group(name)captures the matching slice.left + rightconcatenates sequence patterns.
Parentheses are useful because multiplication binds more tightly than concatenation:
pattern = ["("] + (int * repeat(min=1)) * group("items") + [")"]
Development
Run the test suite with Nox and uv:
uvx nox -s tests
The test suite includes doctests and a set of object-pattern tests adapted from CPython's regular-expression tests.
License
Python Pattern Matching is copyright 2015–2026 Grant Jenks and licensed under the Apache License, Version 2.0.
Release files for patternmatching 3.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| patternmatching-3.1.0.tar.gz | 14.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| patternmatching-3.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.0 kB
Release files / patternmatching-3.1.0.tar.gz
| Download URL | patternmatching-3.1.0.tar.gz |
|---|---|
| Size | 14.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c864eb57af979993181653a21fceeac16d0ec2599df152b2cbf38f91c0e2375e
|
|
BLAKE2b-256 checksum How to use checksums |
376676c6fe9cda989bfe8d1fa55336dcba3c60a96c700380176df646254f9637
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logRelease files / patternmatching-3.1.0-py3-none-any.whl
| Download URL | patternmatching-3.1.0-py3-none-any.whl |
|---|---|
| Size | 10.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5d41e8806efbd07a2d559ed0c156396dc552841f08b15e2b3d3b08dfbd36e433
|
|
BLAKE2b-256 checksum How to use checksums |
2398082db6f3453e5054146fe1f9fc4b06fe7dc9aaf51dc3a50be534faf2f494
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency log