Открыть список
Как стать автором
Обновить

Комментарии 28

Хорошая новость!
Всегда поражало, что в Python нет аналога switch/case. Теперь отпустило :)

Вообще-то есть, легко гуглится, просто имплементируется так, что там больше 10 строк, потому сложнА

И медленнА, и не естественнА и чем так лучше уж без.
А это похоже на switch и читаемость будет получше, но в switch всегда была фишка в быстром сопоставлении, если здесь генерируется код аналогичный лесенке из if-ов(всегда, без оптимизированных исключений), то ценность этой фичи весьма умеренная… а после того как 7-ку дропнули, просто ещё и не светит)
И медленнА

Вы тестировали? Предоставьте бенчмарки.
и не естественнА

Вам, видимо, яснее, в каком направлении двигаться Python, чтобы было естественно…
Если что, про медленно это про словарь функций… Тестировал. Не быстро. И неестественно. Решение противоречит дзену питона, так что не я решаю))
Pattern matching соответствует, но цепочка if-ов это по прежнему не быстро.

import time

def switcher(condition):
    lambdadict = {13:lambda x, y: x+y,
                  12:lambda x, y: x*y,
                  16:lambda x, y: x/y,
                  1:lambda x, y: x**y}
    return lambdadict[condition] if condition in lambdadict else lambda x, y: x

def test_switcher(inp):
    A = 0
    for n,i,j in inp:
        A += switcher(n)(i, j)
    return A

def test_ifs(inp):
    A = 0
    for n,i,j in inp:
        if n == 1: A += i**j
        elif n == 12: A += i*j
        elif n == 13: A += i+j
        elif n == 16: A += i/j
        else: A += i
    return A


funcs = (1, 12, 13, 16, 2432)
inp = [(funcs[n % 5], funcs[n % 5]//3, n) for n in range(10000)]


test_ifs(inp)
test_switcher(inp)

times = 0
A = 0
for i in range(1000):
    t1 = time.perf_counter_ns()
    A += test_ifs(inp)
    times += time.perf_counter_ns() - t1
times /= 1000
print('ifs test average by 1000 reps: %i ns' %times)

times = 0
A = 0
for i in range(1000):
    t1 = time.perf_counter_ns()
    A += test_switcher(inp)
    times += time.perf_counter_ns() - t1
times /= 1000
print('switcher test average by 1000 reps: %i ns' %times)
input('any')

результат:
ifs test average by 1000 reps: 1908833 ns
switcher test average by 1000 reps: 7090622 ns
В 3.5 раза… это медленно.
Не понял Capture Patterns.
Как связаны greeting и name?
А, кажется понял. Это просто переменные и второй паттерн срабатывает, когда greeting == name.
Нет, это не так — name будет присвоено (если name не было ранее объявлено, то будет объявлено) значение greeting.
Извините, я не понял вы подтвердили мои слова? Если нет, то вот результат выполнения
Python3.10a6
image
Нет, нет, я подтвердил ваши слова. Работает так как вы описали
И все равно непонятно причем тут захват. name это переменная, которая существует до match greeting и ее видно в print(f'Hello {name}'), что ожидаемо, ведь match это просто переписанная иначе цепочка if. Так что куда захватывается?
не обязательно — name может не существовать до match, и как уже было описано выше, то name будет объявлено со значением, равным greeting.
А в чем смысл? Чем это лучше чем
match greeting:
    case "":
        print('Hello my friend')
    case _:
        print(f'Hello  {greeting}')

в случае с wildcard хоть работает ожидаемо. А в случае с case name — переменная name может существовать выше, а позже быть переименована и case name начинает работать как wildcard с именем? Стрельба в ногу какая-то.
Видимо для случаев вида match foo(x):…
Гм. Могли ведь и walrus использовать.
match name:=foo(x):
    case _:
        print(f'Hello  {name}')

Вчера как раз собрал 3.10.0a6 под Linux. Давно ждал этой штуки. Только пока в VS Code не подвезли поддержку этой конструкции. К примеру — если написать def myfunc(): и нажать Enter, то курсор перенесется на новую строку и отступит 4 пробела. Если же написать match status: и нажать на Enter, то курсор перенесется в начало новой строки. Немного напрягает.
Перечитал примеры дважды, но… аналог switch-case — единственный, понятный с первого взгляда.
Всё остальное, похоже, имеет подводные камни или просто делает не то, что кажется.
Пока что по сравнению с этим цепочка if-else более понятна.
Не совсем так.

В блоке
if cond1:
    state1
elif cond2:
    state2
else:
    state_default

cond1 не обязательно тождественно cond2!

Вдобавок cond1 может быть любым условием, а не обязательно условием вида a == b.

Таким образом при match-case варианте меньше когнитивная нагрузка. А снижение когнитивной нагрузки — это всегда хорошо. Мы чаще читаем код, а не пишем его.

Я не спорю что цепочка if-else более универсальна.
Но речь о случае, когда условия действительно однородны.
В частности, особенно проблематичны sequence и mapping patterns.
По мне так if len(args) == 2 and ('kwarg' in kwargs): понятнее, чем предлагаемый синтаксис, даже с поправкой на лишнюю пару строчек для распаковки искомых значений.

Capture Patterns — это огромная мина замедленного действия, потому что вынос литерала в константу резко меняет поведение кода но только для некоторых случаев (если имя — не dotted name). Это очень неочевидно и будет провоцировать ошибки.

Секундочку, сопоставление с образцом не будет таковым если его нельзя присвоить переменной(expression vs statement). Если сопоставление с образцом это выражение то это ОК а если statement то это просто кровавый switch на стероидах. Не совсем понятно как это будет сделано.

Предложение сделать это expression было отвергнуто (в принципе, по понятной причине — это бы не вписывалось в общую концепцию языка), так что это действительно просто switch на стероидах, а не настоящий паттерн матчинг как, например, в эрланге.

Мда, жаль конечно.

По-моему expression можно сделать через перегрузку…
Пугают «Capture Patterns» и «Mapping Patterns»… ИМХО — редкостная хрень. Надеюсь, что это не будет использоваться…
Оно будет из коробки работать во всех фреймворках? Или нужно будет делать либы?
Это новый синтаксис языка — оно будет работать везде, начиная с 3.10
Саму концепцию сложно назвать новой, она уже реализована во многих языках, причём как нового поколения (Rust, Golang), так и у тех, кому уже за 0x18 (Java).

А можно примерчик паттерн-матчинга в Golang и Java?

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.