Comments 15
Я за S.O.L.I.D. поэтому считаю что данная функциональность будет только замедлять и нарушает OCP. Схожую функциональность можно элегантно реализовать через словари, а работают они быстрее чем множественные операторы сравнения.
В соответствующем PEP-0622 есть отличный пример:
if (
isinstance(value, (list, tuple)) and
len(value) > 1 and
isinstance(value[-1], (Promise, str))
):
*value, label = value
value = tuple(value)
else:
label = key.replace('_', ' ').title()
vs
match value:
case [*v, label := (Promise() | str())] if v:
value = tuple(v)
case _:
label = key.replace('_', ' ').title()
У второго варианта читаемость намного выше.
Причем здесь SOLID и OCP — непонятно, оба этих принципа никак не нарушаются. Словари, опять же, не всегда дают ту же выразительность, как pattern matching.
Если можно будет делать что-то вроде такого:
elementsAreEqual = lambda aTuple:
match aTuple:
case (x,x): print("обе части одинаковы")
case (_,_): print("обе части разные")
то это уже интереснее.
Я с большим скепсисом смотрел на эту фичу во время обсуждения. После появляения скепсис остался. Основная проблема — pattern matching не exhaustive. Дополнительные проблемы: т.к. типизация в рантайме, полный комплект runtime ошибок сохраняется в полный рост (включая has no attribute 'type' и т.д.). Сочетание интроспекции и возможность переопределять магические методы интроспекции ведёт к тому, что написанному верить очень трудно.
Вот, например, слегка модифицированный ваш код:
match media_object:
case Video():
raise ValueError("Не получается извлечь кадры из видео")
case Image(type="jpg"):
# Вернуть как есть
return media_object
case Image(type="png") | Image(type="gif"):
return render_as(media_object, "jpg")
Вопрос: если type — это getter (декоратор @property
), то когда он вызовется? Например, если media_object Video, будет ли вызван геттер?
Очень провисающая конструкция, которая получилась, когда изящную конструкцию из прочных языков перетащили в мягкий язык.
Как если бы кто-то попытался из пластилина сделать проволочную модель (например, машинки). Пластилин очень плохо подходит для имитации проволоки. Очень плохо.
Ну, это и есть признак "мягкого языка". Утиная типизация (в отличие от системы трейтов, в том же Rust'е) не подразумевает полноты знания. Мы берём минимально возможное что нам нужно, игнорируя остальное. Как только мы говорим про "исчерпание", мы подразумеваем полное знание.
Метод реализации (компиляция или интерпретация) тут вторичен. Основное — разное отношение к строгости. В питоне строгость минимальна (но она есть, в отличие от безумий php или js), в Rust — максимальна. (оба слова не оценивающие, а квалифицирующие). Питон проверяет только то, что нужно для выполнения операции, Rust проверяет всё (почти всё, но то, что он не проверяет — это временные недостатки языка). Соответственно, в рамках этой модели Питон не может проверить exhaustive, а Rust — может.
Точнее, питон мог бы поднимать ValueError, если не сработал ни один case в runtime, но это сильно бы противоречило духу написанного (расширенный if).
В целом, моё мнение, конструкция сыровата и дзен питона подмывает.
Tl;DR отсутствие проверяемого атрибута - штатная ситуация. Property он или нет, сути не меняет
Ответ в первом абзаце https://www.python.org/dev/peps/pep-0622/#id60
Структурированное сопоставление с шаблонами в Python 3.10