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.5. Однако встроенного типа «матрица» в Python нет, и ни один из встроенных типов эти операторы не реализует. Поэтому, быть может, о нем и не рассказывают на курсах.

Однако оператор @ рекомендуется для умножения матриц в библиотеке numpy:

>>> import numpy as np
>>> a = np.array( [ [1, 2], [-2, 3] ] )
>>> b = np.array( [ [3, 0], [1, -3] ] )
>>> a @ b
array([[ 5, -6],
       [-3, -9]])
>>> np.matmul(a, b)
array([[ 5, -6],
       [-3, -9]])

⚠️ Обратите внимание, что это именно np.matmul, а не np.dot!

Также вы можете написать реализацию операторов @ и @= для своих классов. Для этого вам понадобятся магические методы matmul__, __imatmul__, __rmatmul__ . Смотрите пример по ссылке.

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

🔢 Приоритет операций

В языках программирования и в математике вычисление выражений производится в определенном порядке. Порядок этот задается приоритетом операторов и скобками. Со школы мы знаем, что умножение имеет более высокий приоритет, чем сложение, поэтому в пределах одних скобок сначала будет выполнено умножение, а затем только сложение:

2 * 2 + 2 = 6

Рассмотрим таблицу приоритета операций в языке Python. Сверху таблицы самые приоритетные операции, снизу – операции с низким приоритетом.

ОперацияОписание
( )Скобки
**Экспонента (возведение в степень)
+x, -x, ~xУнарные плюс, минус и битовое отрицание
*, /, //, %Умножение, деления, взятие остатка
+, —Сложение и вычитание
<<, >>Битовые сдвиги
&Битовое И
^Битовое исключающее ИЛИ (XOR)
|Битовое ИЛИ
==, !=, >, >=, <, <=,
is, is not,
in, not in
Сравнение, проверка идентичности,
проверка вхождения
notЛогическое НЕ
andЛогическое И
orЛогическое ИЛИ

Как видно, скобки самые главные. Скобки решают все.

Если в одном выражении идут операторы одинакового приоритета, то вычисления выполняются слева направо.

Исключение составляет оператор **. Он право-ассоциативный. Т.е. в цепочке из двух ** сначала выполнится правый, а потом левый.

>>> 3 ** 4 ** 2
43046721
>>> 3 ** (4 ** 2)
43046721
>>> (3 ** 4) ** 2
6561

Обратите внимание на приоритеты not, and и or.

not a or b and c   ===   (not a) or (b and c)

Правила хорошего тона: не составляйте очень сложных выражений и логических выражений; всегда разбивайте их на части. Даже если вы прекрасно знаете приоритеты операций, то программист, читающий ваш код после вас, может знать их плохо; поэтому НЕ пренебрегайте скобками.

В случае с операторами сравнения, помните про цепочки сравнений!

         x < y < z
это ни   (x < y) < z,
ни       x < (y < z),
а        x < y and y < z

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