Make Python Classes Matchable With __match_args__
Learn how to use Python's __match_args__ special attribute to enable positional pattern matching on your custom classes, making match statements cleaner and more intuitive.
Matching Made Personal: How Python's __match_args__ Lets You Pattern Match Your Classes
You've probably used Python's structural pattern matching since it arrived in 3.10, matching tuples, lists, and dictionaries with that clean match ... case syntax. But here's something PythonSkillset readers often miss: you can teach your own classes how to be matched.
The Problem Pattern Matching Solves
Imagine you're building a data pipeline at PythonSkillset, processing thousands of customer records. You've got a custom Customer class with fields like name, email, and signup_date. Without __match_args__, pattern matching against this class would feel clunky at best.
class Customer: def init(self, name, email, signup_date): self.name = name self.email = email self.signup_date = signup_date
Now try to match it:
match customer: case Customer(name='Alice', email=email): print(f"Found Alice at {email}")
This works—but only with keyword patterns. What if you want positional matching, like you do with tuples?
Enter __match_args__
This special attribute tells Python which class attributes to use for positional pattern matching. Think of it as the "positional argument blueprint" for your class.
class Customer: match_args = ('name', 'email', 'signup_date')
def __init__(self, name, email, signup_date):
self.name = name
self.email = email
self.signup_date = signup_date
Now you can match it both ways:
match customer: case Customer('Alice', email, signup_date): print(f"Alice signed up on {signup_date}")
Notice how name is matched positionally because it's first in __match_args__, while email and signup_date are captured. You can still use keyword matching alongside—Python doesn't make you choose.
A Real-World Example from PythonSkillset's Dashboard
Let's make this concrete. Suppose PythonSkillset runs a subscription service with different plan types.
class Subscription: match_args = ('plan', 'price', 'active')
def __init__(self, plan, price, active=True):
self.plan = plan
self.price = price
self.active = active
Now imagine processing subscription renewals:
def process_renewal(subscription): match subscription: case Subscription('basic', price, True): print(f"Basic plan renewing at ${price}") case Subscription('pro', , False): print("Reactivating pro subscription") case Subscription(, , False): print("General reactivation") case : print("No match found")
Clean, readable, and intuitive. Your custom class acts like a built-in type during pattern matching.
What __match_args__ Doesn't Do
This attribute only handles positional matching. It won't:
- Validate types of matched values
- Increase performance (it's just metadata)
- Prevent you from also using keyword patterns
You still need to write your class properly—__match_args__ is a convenience, not a magic wand.
The Bottom Line
Adding __match_args__ to your classes is a small change with big readability payoffs. It makes your custom objects feel native in match statements, letting you write cleaner branching logic. PythonSkillset developers who adopt this pattern find their code easier to follow and maintain.
Next time you're building a class that could benefit from pattern matching, ask yourself: "Would positional matching make sense here?" If yes, list those attributes in __match_args__ and watch your code transform from boilerplate-heavy to beautifully expressive.
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.