Search code examples
pythontypeerroriterableabcstructural-pattern-matching

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


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:


Solution

  • 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.