Python 3.8 здесь!

3.8

🐍Отложим дела ради классной новости! Python версии 3.8 официально релизнулся!

Что в новой версии?

1️⃣ Оператор морж (писал о нем ранее). Присваивание переменной внутри других выражений:

if (n := len(a)) > 10:
    print("слишком длинно")

while (block := f.read(256)) != '':
    process(block)

[clean_name.title() for name in names
 if (clean_name := normalize('NFC', name)) in allowed_names]

2️⃣ Разделитель позиционных аргументов (слэш /). Указывает, что первые несколько аргументов могут быть только позиционными (в строгом порядке, без указания имени). Напомню, что именные аргументы передаются с указанием имени, и не важно в каком порядке. В примере ниже a и b – только позиционные, c и d — могут быть позиционные или переданы по имени, а e и f – исключительно именные:

def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)

# разрешенный вызов:
f(10, 20, 30, d=40, e=50, f=60)

# НЕЛЬЗЯ передать b по имени 
# (b стоит до слэша)
f(10, b=20, c=30, d=40, e=50, f=60) 

# НЕЛЬЗЯ передать e без указания имени
# (e стоит после звездочки)
f(10, 20, 30, 40, 50, f=60) 

3️⃣ Спецификатор = для f-строк. Тут проще на примере, раньше мы писали с повторами:

>>> user = 'eric_idle'
>>> since = date(1975, 7, 31)
>>> f'user={user} since={since}'
"user='eric_idle' since=datetime.date(1975, 7, 31)"

А теперь можно так:

>>> f'{user=} {since=}'
"user='eric_idle' since=datetime.date(1975, 7, 31)"

После знака равно можно добавлять и прочие спецификаторы форматирования:

>>> delta = date.today() - since
>>> f'{user=!s} {delta.days=:,d}'
'user=eric_idle delta.days=16,075'

Для отладки принтами — просто восторг!

4️⃣ Теперь можно continue внутри finally

Еще есть множество улучшений со стороны C-API, всякие хуки аудита, вектор-коллы. Новая настройка PYTHONPYCACHEPREFIX, чтобы вынести кэш байткода из стандартной директории pycache куда вам удобно. Очень-очень много разных мелких изменений в стандартных модулях и функциях, о которых расскажу при случае.

Что нового по-английски

Как вам новая версия?

В Python 3.8 будет оператор «морж»

Морж сидит на льдине на фоне моря

Python 3.8 все еще в разработке, но уже можно полистать список грядущих изменений, и, пожалуй, самое значимое из них (и возможно единственное заметное изменение) – ввод нового оператора присваивания := (морж). Старички вспомнили Паскаль. Смысл этого оператора – дать имя результату выражения. Т.е. вычисляем правую часть моржа, связываем с именем переменной слева и возвращаем результат моржа наружу.

Раньше делали так:

x = len(s)
if x:
    print(x)

Будем делать так:

if x := len(s):  # можно в 3.8
    print(x)

Мотивация введения оператора := состоит в том, что уже наработано много примеров кода, когда он делает запись более лаконичной, не вызывая при этом повторного вычисления выражений.

📎 Пример. Используем вычисленное однажды значение f(x) под именем y:

[y := f(x), y**2, y**3]

📎 Пример. Читаем, сохраняем в chunk и сразу проверяем условие цикла:

while chunk := file.read(8192):
   process(chunk)

📎 Пример. Можно применить в проходах по спискам, чтобы дважды не вычислять f(x):

filtered_data = [y for x in data if (y := f(x)) is not None]

📎 Примеры можно/нельзя:

x := 5    # нельзя
(x := 5)  # можно
x = y := 0  # нельзя
x = (y := 0)  # можно

Приоритет запятой возле нового оператора. Сравните:

x = 1, 2     # x -> (1, 2)
(x := 1, 2)  # x -> 1

P.S.: Казалось бы, почему не сделать так: if x = len(s)? Ответ: чтобы не путать с if x == len(s). В C-подобных языках это частая проблема.

Специально для канала @pyway.