Pattern matching to check a protocol. Getting TypeError: called match pattern must be a type

868 Views Asked by At

I need to match cases where the input is iterable. Here's what I tried:

from typing import Iterable

def detector(x: Iterable | int | float | None) -> bool:
    match x:
        case Iterable():
            print('Iterable')
            return True
        case _:
            print('Non iterable')
            return False

That is producing this error:

TypeError: called match pattern must be a type

Is it possible to detect iterability with match/case?

Note, these two questions address the same error message but neither question is about how to detect iterability:

1

There are 1 best solutions below

0
On BEST ANSWER

The problem is the typing.Iterable is only for type hints and is not considered a "type" by structural pattern matching. Instead, you need to use an abstract base class for detecting iterability: collections.abc.Iterable.

The solution is distinguish the two cases, marking one as being a type hint and the other as a class pattern for structural pattern matching:

def detector(x: typing.Iterable | int | float | None) -> bool:
    match x:
        case collections.abc.Iterable():
            print('Iterable')
            return True
        case _:
            print('Non iterable')
            return False

Also note that at the time of this writing mypy does not support the match statement.