Использование Iterable в сложных паттернах

Можно ли в Python создать шаблон, внутри которого использовалась бы абстракция итерируемого объекта? Например, интуитивно понятен код:

from typing import Iterable

match value:
    case slice(Iterable(), Iterable(), Iterable()):
        ...

Но он не работает. Если отложить в сторону, что в паттерне slice нужно именовать параметры, то основная проблема связана с тем, что typing.Iterable не является типом.

Вижу две альтернативы. Одна из них - перечислять конкретные типы параметров:

match value:
    case slice(start = list() | tuple() | ..., 
               stop  = list() | tuple() | ..., 
               step  = list() | tuple() | ...):
        ...

И здесь напрашивается вопрос, а нельзя ли перечисление указать в одном месте и ссылаться на него по мере необходимости?

Вторая альтернатива - добавлять проверку isinstance для соответствующих параметров:

match value:
    case slice(start=x, stop=y, step=z) if all(isinstance(param, Iterable) 
                                               for param in [x, y, z]):
        ...

Но возникает проблема, если какие-то параметры приемлемы не только как итерируемые, что-то вроде:

    case my_class(Iterable(), Iterable() | int()): ...

Понимаю, что можно вернуться к привычным if-elif-else, но хочется верить, что в конструкции match-case можно что-то придумать.


Ответы (1 шт):

Автор решения: Stanislav Volodarskiy

Работает, если импортировать Iterable из collections.abc:

from collections.abc import Iterable


class C:
    __match_args__ = 'start', 'stop', 'step'

    def __init__(self, start, stop, step):
        self.start = start
        self.stop = stop
        self.step = step

    def __str__(self):
        return f'C({self.start}, {self.stop}, {self.step})'


for c in (C([], [], []), C((), (), ()), C([], [], 3), C(1, 2, 3)):
    match c:
        case C(Iterable(), Iterable(), Iterable() | int()):
            print('match', c)
        case _:
            print('nope', c)
$ python match.py
match C([], [], [])
match C((), (), ())
match C([], [], 3)
nope C(1, 2, 3)
→ Ссылка