Использование 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 шт):
Работает, если импортировать 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)