Raymond Hettinger
Raymond Hettinger

Reputation: 226221

Convert multiple isinstance checks to structural pattern matching

I want to convert this existing code to use pattern matching:

if isinstance(x, int):
    pass
elif isinstance(x, str):
    x = int(x)
elif isinstance(x, (float, Decimal)):
    x = round(x)
else:
    raise TypeError('Unsupported type')

How do you write isinstance checks with pattern matching, and how do you test against multiple possible types like (float, Decimal) at the same time?

Upvotes: 49

Views: 19691

Answers (2)

Raymond Hettinger
Raymond Hettinger

Reputation: 226221

Example converted to pattern matching

Here's the equivalent code using match and case:

match x:
    case int():
        pass
    case str():
        x = int(x)
    case float() | Decimal():
        x = round(x)
    case _:
        raise TypeError('Unsupported type')

Explanation

PEP 634, available since Python 3.10, specifies that isinstance() checks are performed with class patterns. To check for an instance of str, write case str(): .... Note that the parentheses are essential. That is how the grammar determines that this is a class pattern.

To check multiple classes at a time, PEP 634 provides an or-pattern using the | operator. For example, to check whether an object is an instance of float or Decimal, write case float() | Decimal(): .... As before, the parentheses are essential.

Upvotes: 67

Kavindu Ravishka
Kavindu Ravishka

Reputation: 819

Using python match case

Without Exception handling

match x:
    case int():
        pass
    case str():
        x = int(x)
    case float() | Decimal():
        x = round(x)
    case _:
        raise TypeError('Unsupported type')

Some extras

There are still some flows in this code.

With exception handling

match x:
    case int():
        pass
    case str():
        try:
            x = int(x)
        except ValueError:
            raise TypeError('Unsupported type')
    case float() | Decimal():
        x = round(x)
    case _:
        raise TypeError('Unsupported type')

As a function

def func(x):
    match x:
        case int():
            pass
        case str():
            try:
                x = int(x)
            except ValueError:
                raise TypeError('Unsupported type')
        case float() | Decimal():
            x = round(x)
        case _:
            raise TypeError('Unsupported type')
    return x

Upvotes: 5

Related Questions