You want to match against a constant value. That's a case for constant value patterns:

match typ:
    case somemodule.ClassOne:
        ...
    case anothermodule.ClassTwo:
        ...

Constant value patterns must be of the form NAME ('.' NAME)+ - that is, a name followed by at least one attribute lookup. A bare name will be considered a capture pattern. That's fine for classes defined in other modules, but if you want to match against classes in the same module, you can import the current module:

# in somemodule.py
import somemodule

class ClassOne:
    ...
class ClassTwo:
    ...

match typ:
    case somemodule.ClassOne:
        ...
    case somemodule.ClassTwo:
...

or if you want to avoid the circular import, you can create a namespace:

import types

options = types.SimpleNamespace()
options.ClassOne = ClassOne
options.ClassTwo = ClassTwo

match typ:
    case options.ClassOne:
        ...
    case options.ClassTwo:
        ...

Note that if you go the "import the current module" route, you need to be aware of Python's weird thing where the entry point script is considered the __main__ module, regardless of its file name. If you do python somefile.py and try to import somefile inside that, it will perform a second run of somefile.py as the somefile module and create a second copy of all your classes, and your match statements won't work.

Answer from user2357112 on Stack Overflow
๐ŸŒ
GeeksforGeeks
geeksforgeeks.org โ€บ python โ€บ python-match-case-statement
Python Match Case Statement - GeeksforGeeks
December 11, 2025 - Let's take a look at python match case statement in detail: The match-case syntax is based on structural pattern matching, which enables matching against data structures like sequences, mappings and even classes, providing more granularity and ...
Top answer
1 of 4
15

You want to match against a constant value. That's a case for constant value patterns:

match typ:
    case somemodule.ClassOne:
        ...
    case anothermodule.ClassTwo:
        ...

Constant value patterns must be of the form NAME ('.' NAME)+ - that is, a name followed by at least one attribute lookup. A bare name will be considered a capture pattern. That's fine for classes defined in other modules, but if you want to match against classes in the same module, you can import the current module:

# in somemodule.py
import somemodule

class ClassOne:
    ...
class ClassTwo:
    ...

match typ:
    case somemodule.ClassOne:
        ...
    case somemodule.ClassTwo:
...

or if you want to avoid the circular import, you can create a namespace:

import types

options = types.SimpleNamespace()
options.ClassOne = ClassOne
options.ClassTwo = ClassTwo

match typ:
    case options.ClassOne:
        ...
    case options.ClassTwo:
        ...

Note that if you go the "import the current module" route, you need to be aware of Python's weird thing where the entry point script is considered the __main__ module, regardless of its file name. If you do python somefile.py and try to import somefile inside that, it will perform a second run of somefile.py as the somefile module and create a second copy of all your classes, and your match statements won't work.

2 of 4
6

Try using typ() instead of typ in the match line:

        class aaa():
            pass

        class bbb():
            pass

        def f1(typ):
            if typ is aaa:
                print("aaa")
            elif typ is bbb:
                print("bbb")
            else:
                print("???")

        def f2(typ):
            match typ():
                case aaa():
                    print("aaa")
                case bbb():
                    print("bbb")
                case _:
                    print("???")

        f1(aaa)
        f1(bbb)
        f2(aaa)
        f2(bbb)        

Output:

aaa
bbb
aaa
bbb

UPDATE:

Based on OP's comment asking for solution that works for classes more generally than the example classes in the question, here is an answer addressing this:

class aaa():
    pass

class bbb():
    pass

def f1(typ):
    if typ is aaa:
        print("aaa")
    elif typ is bbb:
        print("bbb")
    else:
        print("???")

def f2(typ):
    match typ.__qualname__:
        case aaa.__qualname__:
            print("aaa")
        case bbb.__qualname__:
            print("bbb")
        case _:
            print("???")

f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)

Output:

aaa
bbb
aaa
bbb

UPDATE #2: Based on this post and some perusal of PEP 634 here, I have created an example showing how a few data types (a Python builtin, a class from the collections module, and a user defined class) can be used by match to determine an action to perform based on a class type (or more generally, a data type):

class bbb:
    pass

class namespacing_class:
    class aaa:
        pass


def f1(typ):
    if typ is aaa:
        print("aaa")
    elif typ is bbb:
        print("bbb")
    else:
        print("???")

def f2(typ):
    match typ.__qualname__:
        case aaa.__qualname__:
            print("aaa")
        case bbb.__qualname__:
            print("bbb")
        case _:
            print("???")

def f3(typ):
    import collections
    match typ:
        case namespacing_class.aaa:
            print("aaa")
        case __builtins__.str:
            print("str")
        case collections.Counter:
            print("Counter")
        case _:
            print("???")

'''
f1(aaa)
f1(bbb)
f2(aaa)
f2(bbb)
'''
f3(namespacing_class.aaa)
f3(str)
import collections
f3(collections.Counter)

Outputs:

aaa
str
Counter

As stated in this answer in another post:

A variable name in a case clause is treated as a name capture pattern. It always matches and tries to make an assignment to the variable name. ... We need to replace the name capture pattern with a non-capturing pattern such as a value pattern that uses the . operator for attribute lookup. The dot is the key to matching this a non-capturing pattern.

In other words, if we try to say case aaa: for example, aaa will be interpreted as a name to which we assign the subject (typ in your code) and will always match and block any attempts to match subsequent case lines.

To get around this, for class type names (or names generally) that can be specified using a dot (perhaps because they belong to a namespace or another class), we can use the dotted name as a pattern that will not be interpreted as a name capture.

For built-in type str, we can use case __builtins__.str:. For the Counter class in Python's collections module, we can use case collections.Counter:. If we define class aaa within another class named namespacing_class, we can use case namespacing_class.aaa:.

However, if we define class bbb at the top level within our Python code, it's not clear to me that there is any way to use a dotted name to refer to it and thereby avoid name capture.

It's possible there's a way to specify a user defined class type in a case line and I simply haven't figured it out yet. Otherwise, it seems rather arbitrary (and unfortunate) to be able to do this for dottable types and not for non-dottable ones.

๐ŸŒ
Python
peps.python.org โ€บ pep-0622
PEP 622 โ€“ Structural Pattern Matching | peps.python.org
There are two possible ways of ... Each item in a class pattern can be an arbitrary pattern. A simple example: match shape: case Point(x, y): ......
๐ŸŒ
Python
peps.python.org โ€บ pep-0636
PEP 636 โ€“ Structural Pattern Matching: Tutorial | peps.python.org
class Click: __match_args__ = ("position", "button") def __init__(self, pos, btn): self.position = pos self.button = btn ... The __match_args__ special attribute defines an explicit order for your attributes that can be used in patterns like ...
๐ŸŒ
Python Morsels
pythonmorsels.com โ€บ match-case-parsing-python
Appreciating Python's match-case by parsing Python code - Python Morsels
June 22, 2022 - Python's match-case blocks are complex structural pattern matching tools that are often more hassle than they're worth. But they're great for parsing abstract syntax trees.
๐ŸŒ
Readthedocs
pc-python.readthedocs.io โ€บ en โ€บ latest โ€บ python_advanced โ€บ match_case.html
6. Match - Case โ€” PC-Python
In executing do_action("use sword", weapons), the first case statement will check to see if the weapon, sword, is in the weapons list. The second action with the crossbow will result in the print statement indicating that the weapon canโ€™t be used. def do_action(action, weapons): match action.split(): case ["use", weapon] if weapon in weapons: print(f"using {weapon}") case ["use", _]: print(f"Can't use that weapon.") weapons = ["dagger", "sword", "spear"] do_action("use sword", weapons) do_action("use crossbow", weapons)
๐ŸŒ
W3Schools
w3schools.com โ€บ python โ€บ python_match.asp
Python Match
The match statement is used to perform different actions based on different conditions. Instead of writing many if..else statements, you can use the match statement. The match statement selects one of many code blocks to be executed. match ...
Find elsewhere
๐ŸŒ
Plain English Westminster
benhoyt.com โ€บ writings โ€บ python-pattern-matching
Structural pattern matching in Python 3.10
Python evaluates the match expression, and then tries each case from the top, executing the first one that matches, or the _ default case if no others match. But hereโ€™s where the structural part comes in: the case patterns donโ€™t just have to be literals. The patterns can also: ... Wow!
Top answer
1 of 2
73

Rather than match type(v), match v directly:

values = [
    1,
    "hello",
    True,
]

for v in values:
    match v:
        case str():
            print("It is a string!")
        case bool():
            print("It is a boolean!")
        case int():
            print("It is an integer!")
        case _:
            print(f"It is a {type(v)}!")

Note that I've swapped the order of bool() and int() here, so that True being an instance of int doesn't cause issues.

This is a class pattern match.

2 of 2
11

You can match directly against the type of v, but you need a value pattern to refer to the types to match, as a "dotless" name is a capture pattern that matches any value. For example,

import builtins


values = [
    1,
    "hello",
    True
]

# Caveat: this will continue to work even if someone
# rebinds the built-in, but not, for example, if builtins.str
# itself is rebound.
for v in values:
    match type(v):
        case builtins.str:
            print("It is a string!")
        case builtins.int:
            print("It is an integer!")
        case builtins.bool:
            print("It is a boolean!")
        case _:
            print(f"It is a {type(v)}!")

Note that a value pattern must be a dotted name; it's not an arbitrary expression that can evaluate to a specific value.

(Whether you really want to match against the actual type of a value, or really want to determine if a value is an instance of a given type, is another matter. In the latter case, an if-elif statement is needed.

if isinstance(v, bool):
    print("It is a boolean!")
elif isinstance(v, int):
    print("It is an int!")
elif isinstance(v, str):
    print("It is a string!")
else:
    print(f"It is a {type(v)}!")

There is no pattern that lets you use the result of calling isinstance as the case to match against. )

๐ŸŒ
Medium
lynn-kwong.medium.com โ€บ clean-up-your-if-else-python-match-case-explained-for-beginners-3aa29b442091
Clean Up Your if/else: Python match/case Explained for Beginners | by Lynn G. Kwong | Nov, 2025 | Medium | Medium
November 29, 2025 - Instead of chaining many if/elif tests, match takes one subject value and compares it to each case pattern in turn. The first matching case runs, and you can include a final case _: (underscore) as a catch-all default.
๐ŸŒ
Gui Commits
guicommits.com โ€บ python-match-case-examples
Python Match Case Examples ๐Ÿ๐Ÿ•น๏ธ
September 7, 2022 - Python 3.10 has the match case which is Structural Pattern Matching. I'm going to show you what it can do with examples!
๐ŸŒ
Towards Data Science
towardsdatascience.com โ€บ home โ€บ latest โ€บ the match-case in python 3.10 is not that simple
The Match-Case In Python 3.10 Is Not That Simple | Towards Data Science
January 21, 2025 - Then, letโ€™s create some objects from the class for testing. d1 = Direction('east', 'south') d2 = Direction(vertical='north') d3 = Direction('centre', 'centre') The results show that the match-case can easily match these objects based on their attributes! ... In this article, I have introduced the new syntax "match-case" that is introduced in Python 3.10, and how flexible and powerful it is.
๐ŸŒ
AlgoMaster
algomaster.io โ€บ learn โ€บ python โ€บ match-case
Match Case | Python | AlgoMaster.io | AlgoMaster.io
At its core, the match-case construct allows you to compare a value against different patterns and execute corresponding blocks of code based on which pattern matches. The basic syntax looks like this: Letโ€™s break this down a bit.
๐ŸŒ
LearnPython.com
learnpython.com โ€บ blog โ€บ python-match-case-statement
How to Use a match case Statement in Python 3.10 | LearnPython.com
This is Python 3.10โ€™s most important new feature; the new functionality allows you to more easily control the flow of your programs by executing certain parts of code if conditions (or cases) are met. In this article, weโ€™ll tell you everything you need to know about the match case statement in Python, which will allow you to have fine-grained control over how your programs execute.
๐ŸŒ
DataCamp
datacamp.com โ€บ tutorial โ€บ python-switch-case
Python Switch Case Statement: A Beginner's Guide | DataCamp
December 6, 2024 - Python's match-case differs significantly from traditional switch-case statements found in languages like Java or C++. In Java, for example, the switch statement is limited to matching only scalar values (like integers and enum types), whereas Python's match-case offers a much more flexible pattern matching capability, allowing for matching complex data types, such as sequences and class instances.
๐ŸŒ
Python.org
discuss.python.org โ€บ python help
No/confusing way to use match-case - Python Help - Discussions on Python.org
June 15, 2022 - current scenario - for certain types, there is no way to match them, mppngprxy = (type.__dict__) dct_kys = {'a': 1}.keys() dct_vls = {'a': 1}.values() dct_items = {'a': 1}.items() for i in [mppngprxy, dct_kys, dct_vls, dct_items]: match i: case type(type.__dict__): print('mapping proxy') # it does not work case ???: print('dictionary keys') case ???: print('dictionary values') case ???: print('dictionary items') use of match case on types that could be traversed is also a ...
๐ŸŒ
datagy
datagy.io โ€บ home โ€บ python posts โ€บ python switch (match-case) statements: complete guide
Python Switch (Match-Case) Statements: Complete Guide โ€ข datagy
February 23, 2022 - Are you lost?") case 5: print("Yikes. Something went wrong!") case _: print("Yikers. I don't know that one.") # Returns: # Yikers. I don't know that one. Another incredible feature of Python is the ability to match both a type and a structure. This means that Python can interpret whether an item is, say, an iterable object from which it can extract values.
๐ŸŒ
The Teclado Blog
blog.teclado.com โ€บ python-match-case
Using "match...case" in Python 3.10
October 26, 2022 - Any cases below this case will never run because all cases will match with the underscore case. This is similar to the else keyword in an if...else. The _ case matches everything because Python recognizes _ as a valid variable name. So just like when we matched the case ["hello", name], the comparison expression will get binded to the _ name.
๐ŸŒ
Kanaries
docs.kanaries.net โ€บ topics โ€บ Python โ€บ python-match-case
Python Match Case: Structural Pattern Matching Explained (Python 3.10+) โ€“ Kanaries
3 weeks ago - QUIT_COMMAND = "quit" match user_input: case QUIT_COMMAND: # This captures into QUIT_COMMAND, not compare! print("This always matches!") To match against a constant, use dotted names or literal values: class Commands: QUIT = "quit" HELP = "help" match user_input: case Commands.QUIT: # Dotted name: compares against the value print("Quitting") case Commands.HELP: print("Showing help")