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.

Answer from wim on Stack Overflow
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. )

🌐
Python
peps.python.org › pep-0636
PEP 636 – Structural Pattern Matching: Tutorial | peps.python.org
The __match_args__ special attribute defines an explicit order for your attributes that can be used in patterns like case Click((x,y)). Your pattern above treats all mouse buttons the same, and you have decided that you want to accept left-clicks, and ignore other buttons. While doing so, you notice that the button attribute is typed as a Button which is an enumeration built with enum.Enum.
Discussions

How can you match on a union of types?
I would like to exhaustively match against a union of type[T] | type[V]. For example: from typing_extensions import assert_never def f(t: type[int] | type[float]) -> None: match t: case int: print("it's a int") case float: print("it's a float") case _ as unreachable: assert_never(unreachable) ... More on discuss.python.org
🌐 discuss.python.org
2
May 15, 2023
How to use python's Structural Pattern Matching to test built in types? - Stack Overflow
I'm trying to use SPM to determine if a certain type is an int or an str. The following code: from typing import Type def main(type_to_match: Type): match type_to_match: case str(): ... More on stackoverflow.com
🌐 stackoverflow.com
Opinions on match-case?
Match-case is great for structural pattern matching (which is what it's designed for) but you cannot just replace any and all if statements with match-case. So while the match-case might be more readable in itself, if you blindly go and switch if-else statements to match-case where you can, your code as a whole will become less readable because it keeps jumping from one control flow method to another. So I use match-case in specific cases where I need to match some specific structural pattern, but in most cases I feel it's better to stick with your regular if-else. More on reddit.com
🌐 r/Python
62
16
February 12, 2025
How to do structural pattern matching in Python 3.10 with a type to match? - Stack Overflow
I am trying to match a type in Python 3.10 using the console: t = 12.0 match type(t): case int: print("int") case float: print("float") And I get this error: File... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Python
peps.python.org › pep-0622
PEP 622 – Structural Pattern Matching | peps.python.org
A match statement compares a value (the subject) to several different shapes (the patterns) until a shape fits. Each pattern describes the type and structure of the accepted values as well as the variables where to capture its contents.
🌐
Plain English Westminster
benhoyt.com › writings › python-pattern-matching
Structural pattern matching in Python 3.10
Definitely a win! Syntax tree processing seems like the ideal use case for match. In Python 3.10, the ast module’s node types already have __match_args__ set, so that makes it even cleaner by avoiding Constant(value=value) type of repetition.
🌐
Python.org
discuss.python.org › python help
How can you match on a union of types? - Python Help - Discussions on Python.org
May 15, 2023 - I would like to exhaustively match against a union of type[T] | type[V]. For example: from typing_extensions import assert_never def f(t: type[int] | type[float]) -> None: match t: case int: print("it's a int") case float: print("it's a float") ...
🌐
Python documentation
docs.python.org › 3 › library › re.html
re — Regular expression operations
4 days ago - The technique is to combine those into a single master regular expression and to loop over successive matches: from typing import NamedTuple import re class Token(NamedTuple): type: str value: str line: int column: int def tokenize(code): keywords = {'IF', 'THEN', 'ENDIF', 'FOR', 'NEXT', 'GOSUB', 'RETURN'} token_specification = [ ('NUMBER', r'\d+(\.\d*)?'), # Integer or decimal number ('ASSIGN', r':='), # Assignment operator ('END', r';'), # Statement terminator ('ID', r'[A-Za-z]+'), # Identifiers ('OP', r'[+\-*/]'), # Arithmetic operators ('NEWLINE', r'\n'), # Line endings ('SKIP', r'[ \t]+')
🌐
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.
Find elsewhere
🌐
W3Schools
w3schools.com › python › python_match.asp
Python Match
Python Examples Python Compiler ... Python Certificate Python Training ... The match statement is used to perform different actions based on different conditions....
🌐
Mimo
mimo.org › glossary › python › match-statement
Python Match Statement: A Versatile Switch-Case in Python
def categorize_data_point(value): match value: case value if value < 0: return "Negative" case value if value >= 0 and value <= 10: return "Low" case value if value > 10: return "High" Other programming languages use so-called switch-case statements for similar purposes. However, traditional switch statements often only work with primitive data types like integers and strings. Python allows more complex cases with data structures like lists, tuples, and dictionaries.
🌐
Medium
medium.com › @muhammadshafey063 › python-match-cases-and-their-types-with-uses-0cf2f54cc730
Python: Match cases and their types with uses | by Muhammad shafey | Medium
June 1, 2024 - With its various types, such as Simple Match, Tuple Match, List Match, Dictionary Match, Wildcard Match, and Guard Clause, Match Case provides a robust way to match values against different patterns.
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-match-case-statement
Python Match Case Statement - GeeksforGeeks
December 11, 2025 - If the list does not match either pattern, the wildcard _ is used to print "Unknown data format". A mapping is another common data type in Python and match-case can be used to match against dictionaries, checking for specific keys and values.
🌐
Real Python
realpython.com › structural-pattern-matching
Structural Pattern Matching in Python – Real Python
August 6, 2024 - Now that you’ve seen the most basic form of pattern matching in Python, it’s time to unravel the meaning of a structural pattern. Python supports several types of structural patterns, which you’ll explore in detail throughout this tutorial. Each pattern describes the structure of an object to match, including its type, shape, value, and identity.
Top answer
1 of 4
22

If you just pass a type directly, it will consider it to be a "name capture" rather than a "value capture." You can coerce it to use a value capture by importing the builtins module, and using a dotted notation to check for the type.

import builtins
from typing import Type


def main(type_: Type):
    match (type_):
        case builtins.str:  # it works with the dotted notation
            print(f"{type_} is a String")
        case builtins.int:
            print(f"{type_} is an Int")
        case _:
            print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")

if __name__ == "__main__":
    main(type("hello"))  # <class 'str'> is a String
    main(str)  # <class 'str'> is a String
    main(type(42))  # <class 'int'> is an Int
    main(int)  # <class 'int'> is an Int
2 of 4
7

As its name suggests, structural pattern matching is more suited for matching patterns, not values (like a classic switch/case in other languages). For example, it makes it very easy to check different possible structures of a list or a dict, but for values there is not much advantage over a simple if/else structure:

if type_to_match == str:
    print("This is a String")
elif type_to_match == int:
    print("This is an Int")
else:
    print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")

But if you really want to use SPM, you could use the guard feature along with issublcass to check if a type is or is a child of any other:

match type_to_match:
    case s if issubclass(type_to_match, str):
        print(f"{s} - This is a String")
    case n if issubclass(type_to_match, int):
        print(f"{n} - This is an Int")
    case _:
        print("\nhttps://en.meming.world/images/en/0/03/I%27ve_Never_Met_This_Man_In_My_Life.jpg")
🌐
Better Stack
betterstack.com › community › guides › scaling-python › python-pattern-matching
Structural Pattern Matching in Python: A Comprehensive Guide | Better Stack Community
March 27, 2025 - Learn how to use structural pattern matching in Python to simplify complex conditionals and make your code more readable. This guide covers matching with basic types, dictionaries, guard clauses, and more—introduced in Python 3.10 and enhanced ...
🌐
Reddit
reddit.com › r/python › opinions on match-case?
r/Python on Reddit: Opinions on match-case?
February 12, 2025 -

I am curious on the Python community’s opinions on the match-case structure. I know that it has been around for a couple of years now, but some people still consider it relatively new.

I personally really like it. It is much cleaner and concise compared if-elif-else chains, and I appreciate the pattern-matching.

match-case example:

# note that this is just an example, it would be more fit in a case where there is more complex logic with side-effects

from random import randint

value = randint(0, 2)

match value:
    case 0:
        print("Foo")
    case 1:
        print("Bar")
    case 2:
        print("Baz")
🌐
Earthly
earthly.dev › blog › structural-pattern-matching-python
Structural Pattern Matching in Python - Earthly Blog
July 19, 2023 - They include a subject with one of the basic data types (integer, float, string, and Boolean) matched against a pattern of the same data type. The behavior of the match-case statement, in this case, is similar to the switch-case statement in ...
🌐
Python documentation
docs.python.org › 3 › library › typing.html
typing — Support for type hints
1 week ago - In contrast to non-unpacked annotations of *args - e.g. *args: int, which would specify that all arguments are int - *args: *Ts enables reference to the types of the individual arguments in *args. Here, this allows us to ensure the types of the *args passed to call_soon match the types of the ...
Top answer
1 of 4
22

This is a common "gotcha" of the new syntax: case clauses are not expressions. That is, if you put a variable name in a case clause, the syntax assigns to that name rather than reading that name.

It's a common misconception to think of match as like switch in other languages: it is not, not even really close. switch cases are expressions which test for equality against the switch expression; conversely, match cases are structured patterns which unpack the match expression. It's really much more akin to generalized iterable unpacking. It asks the question: "does the structure of the match expression look like the structure of the case clause?", a very different question from what a switch statement asks.

For example:

t = 12.0
match t:
    case newvar: # This is equal to `newvar = t`
        print(f"bound a new variable called newvar: {newvar}")
        # prints "bound a new variable called newvar: 12.00000000"
        # this pattern matches anything at all, so all following cases never run

    case 13.0:
        print("found 13.0")

    case [a, b, c]: # matches an iterable with exactly 3 elements,
        # and *assigns* those elements to the variables `a`, `b` and `c`
        print(f"found an iterable of length exactly 3.")
        print(f"these are the values in the iterable: {a} {b} {c}")

    case [*_]:
        print("found some sort of iterable, but it's definitely")
        print("not of length 3, because that already matched earlier")

    case my_fancy_type(): # match statement magic: this is how to type check!
        print(f"variable t = {t} is of type {my_fancy_type}")

    case _:
        print("no match")

So what your OP actually does is kinda like this:

t = 12.0
tt = type(t) # float obviously
match tt:

    case int: # assigns to int! `int = tt`, overwriting the builtin
       print(f"the value of int: {int}")
       # output: "the value of int: <class 'float'>"
       print(int == float) # output: True (!!!!!!!!)
       # In order to get the original builtin type, you'd have to do
       # something like `from builtins import int as int2`

    case float: # assigns to float, in this case the no-op `float = float`
        # in fact this clause is identical to the previous clause:
        # match anything and bind the match to its new name
        print(f"match anything and bind it to name 'float': {float}")
        # never prints, because we already matched the first case

    case float(): # since this isn't a variable name, no assignment happens.
        # under the hood, this equates to an `isinstance` check. 
        # `float` is not an instance of itself, so this wouldn't match.
        print(f"tt: {tt} is an instance of float") # never prints
        # of course, this case never executes anyways because the
        # first case matches anything, skipping all following cases

Frankly, I'm not entirely sure how the under-the-hood instance check works, but it definitely works like the other answer says: by defintion of the match syntax, type checks are done like this:

match instance:
    case type():
        print(f"object {instance} is of type {type}!")

So we come back to where we started: case clauses are not expressions. As the PEP says, it's better to think of case clauses as kind of like function declarations, where we name the arguments to the function and possibly bind some default values to those newly-named arguments. But we never, ever read existing variables in case clauses, only make new variables. (There's some other subtleties involved as well, for instance a dotted access doesn't count as a "variable" for this purpose, but this is complicated already, best to end this answer here.)

2 of 4
17

Lose the type() and also add parentheses to your types:

t = 12.0
match t:
  case int():
    print("int")
  case float():
    print("float")

I'm not sure why what you've wrote is not working, but this one works.

🌐
KooR.fr
koor.fr › Python › Tutorial › python_instruction_match_case.wp
KooR.fr - L'instruction match / case (Python 3.10) - Le tutoriel/cours sur le langage de programmation Python
Dorénavant, Python permet de combiner le pattern matching avec des vérifications de types. Par exemple, case str(): ou case int(): permet de vérifier si la valeur correspond à un type spécifique.
🌐
Buddy
buddy.works › home › tutorials › languages › structural pattern matching in python
Structural Pattern Matching In Python | Tutorials
April 28, 2021 - If any of them is matched, the match succeeds and we return "Number". In an OR pattern, all sub patterns must bind to the same variables. In our example above, the sub patterns bind to val. AS patterns allow us to specify a structure constraint and bind to a value at the same time. In the check_type function that we used to demonstrate OR patterns, notice we repeated the variable val. We can avoid this by rewriting our pattern as an AS pattern: pythondef check_type(val): match val: case str() as val: return "String" case int() | float() as val: return "Number"