Многие пользователи интересуются, что нового появилось в Python версии 3.8. Сегодня будем разбираться в этом более подробно.
Оператор walrus (морж)
Это одна из главных особенностей этой версии языка программирования, которая при этом является одновременно и наиболее спорной. Путь принятия решения о PEP 572 был достаточно ухабистым, что привело к созданию новой модели управления языком.
Представим, что новое правительство уже давно хочет сместить диктатора с именем Гвидо ван Россум после того, как он уйдет в отставку по причине беспорядков, вызванных PEP 572 (то бишь, конфликта между разработчиками из-за обновленного синтаксиса).
Как следствие, выходит новый оператор, который нередко называется «оператор-морж», поскольку он отображается очень специфическим образом. Если использовать := в if или while, то можно присвоить значение переменной непосредственно во время тестирования.
Идея следующая: это даст возможность сделать такие задачи, как сопоставление с несколькими шаблонами, проще.
Ранее был следующий синтаксис:
m = re.match(p1, line) if m: return m.group(1) else: m = re.match(p2, line) if m: return m.group(2) else: m = re.match(p3, line) Теперь же он следующий. if m := re.match(p1, line): return m.group(1) elif m := re.match(p2, line): return m.group(2) elif m := re.match(p3, line): ...
Если говорить о цикле над неповторяемым объектом, то он выглядел так ранее.
ent = obj.next_entry() while ent: ... # process ent ent = obj.next_entry() А теперь так. while ent := obj.next_entry(): ... # process ent
Видим, что действительно стало значительно проще. Эти и другие примеры использования дают возможность прояснить намерения разработчика. Подобная функция имеется в других языках разработки. В целом, это изменение небольшое, и многим кажется странным то количество шума, которое с ним связано.
Поддержка отладки для f-string в Python 3.8
Первые форматируемые строки появились в Python 3.6. Они оказались полезными, например, для отладки вывода. В связи с этим, Эрик В. Смит предложил ввести дополнительный синтаксис для f-строк, чтобы сделать этот процесс еще проще.
Первоначально идея пошла от Ларри Хастингса, и были внесены некоторые изменения, которые задокументированы в двух случаях feature-request на bugs.python.org.
Результат получился таким.
Вместо того, чтобы работать с чем-то большим, типа
print(f'foo={foo} bar={bar}')
Разработчики с этой версии языка программирования могут работать так.
print(f'{foo=} {bar=}')
Независимо от того, какой вариант будет использоваться, результат будет следующим.
foo = 42 bar = 'answer ...' print(f'{foo=} {bar=}') # foo=42 bar=answer ...
Помимо этого, ряд модификаторов может использоваться для коррекции выдачи. !s использует представление str(), вместо значения по умолчанию epr(), а !f может получать доступ к элементам управления форматированием. Они могут использоваться таким образом.
Для примера будем использовать модуль math для работы с математическими функциями.
import datetime import math now = datetime.datetime.now() print(f'{now=} {now=!s}') # Результат: # now = datetime.datetime(2019, 7, 29, 10, 49, 0, 170211) now=2019-07-29 10:49:00.170211 print(f'{math.pi=!f:.2f}') # math.pi=3.14
Еще одна полезная возможность – это сохранение пробелов в выражении f-строк.
a = 37 print(f'{a = }, {a = }') # a = 37, a = 37
В конечном итоге, у разработчиков появляется возможность свои отладки выводить красиво. То же самое касается логирования и других сообщений. Для некоторых эти изменения могут не быть настолько существенными, но реально эффект от них перевешивает ощущаемую ненужность. Ведь мы понимаем, что для многих разработчиков f-строки стали основным механизмом интерполяции.
Позиционные параметры
Это еще одно изменение, которое дает возможность чистым функциям работать с теми же опциями для параметров, которые уже есть в C. PEP 570 вносит обновленный синтаксис, используемый в определениях функций для обозначения исключительно тех параметров, которые не могут передаваться в качестве аргументов ключевых слов. То есть, позиционных аргументов.
Так, вызов функции pow() должен осуществляться с такими аргументами.
pow(2, 3) # 8 pow(x=2, y=3) ... TypeError: pow() takes no keyword arguments
Но если бы pow() являлась чистой функцией Python, что и ожидалось бы альтернативной реализацией языка, это поведение скорректировать было бы непросто. Функция способна принимать исключительно *args и **kwargs, а потом выдвигать условие, что kwargs ничего не содержит. А затем скрывает «намерения» функции.
Есть и ряд других причин, описание которых есть в PEP. Но на практике разработчикам и не нужно с ними часто сталкиваться.
Правда, тем, кому таки приходится, возможно, понравится то, что они могут написать функцию pow() на чистом Python, которая будет иметь такое же поведение, как и встроенная. Вот так, как на этом примере показано.
def pow(x, y, z=None, /): r = x**y if z is not None: r %= z return r
Слэш показывает место коца позиционных аргументов в списке. Суть такая же, как и для *, который может использоваться в списке для делимитации ключевых аргументов (тех, которые могут передаваться как keywords=…).
Приведем еще один пример.
def fun(a, b, /, c, d, *, e, f): ...
Он указывает на то, что a и b должны передаваться позиционально. А c и d могут передаваться как позиционально, так и в виде ключевого слова. e и f должны передаваться в виде ключевого слова.
Итак,
КОД # легально КОД # легально КОД # нелегально fun(1, 2, 3, 4, e=5, f=6) # правильно fun(1, 2, 3, d=4, e=5, f=6) # правильно fun(a=1, b=2, c=3, d=4, e=5, f=6) # неправильно
Похоже, что подавляющее количество разработчиков Python не сталкивались ни с *, ни с /.
Подвижный __pycache__
Директория __pycache__ была создана интерпретатором Python 3.2 и новее для того, чтобы хранить файлы .pyc. В этих файлах содержится байт-код, кешируемый после того, как интерпретатор компилирует файлы .py. Версии Python, которые были выпущены до 3.8 лишь выбрасывали файлы .pyc, но PEP 3147 внесло коррективы в эту ситуацию.
Все делалось для того, чтобы реализовать поддержку множественных версий языка с риском того, что определенные могут вообще отсутствовать. Так что, к примеру, стандартные файлы библиотеки компилируются и кэшируются каждой версией языка.
Каждый записывает файл типа name.interp-version.pyc в __pycache__. Так что, например, на Linux Fedora, foo.py будет компилироваться при первом использовании, и будет создан __pycache__/foo.cpython-37.pyc.
Если говорить об эффективности работы – то по этой части все прекрасно, но такой подход может не подходить по некоторым причинам. Карл Мейер осуществил запрос функции, запрашивая у переменной среды, где файлы кэша находятся и как их внести. Ему пришлось решать проблемы, связанные с доступом в его системе. А файлы кэша в конечном итоге отключались.
Итак, им была добавлена переменная среды PYTHONPYCACHEPREFIX (также доступная через флаг командной строки -X pycache_prefix=PATH), чтобы указать интерпретатору то, что место для этих файлов окажется другим.
Другие обновления языка
Python 3.8 получит более быстрое соглашение о вызовах для расширений C, базируясь на соглашении fastcall, используемого внутри CPython. В версии 3.8 манера экспериментальная, но ожидалось, что итоговый результат мы увидим в версии 3.9. Таким образом, версия 3.9 во многом стала продолжать разработки, которые начали внедряться в версии 3.8.
Также была очищена обработка конфигураций в интерпретаторе. Поэтому теперь есть возможность более простого встраивания языка в другие приложения без надобности в наличии переменных среды и других средств конфигурации, способных помешать стабильной работе системы Python. Это удобно.
Также было добавлено несколько дополнительных возможностей в ряде стандартных модулей библиотеки. Так, для обработки абстрактных древ используется модуль ast. Он получил такие возможности, как составление статистики и ввода.
В черновике документации «что нового в Python 3.8» содержится гораздо большее количество информации об изменениях, которые не были упомянуты ранее.
По поводу статуса PEP 594 определенности еще нет. Идея удаления старых модулей стандартной библиотеки была популярной в течение довольно продолжительного периода времени. PEP была запрошена в мае, и это довольно активно обсуждается с того момента. Удаление надоевших модулей стандартных библиотек не вызывает возражений ровно до того момента, пока не будет удален любимый модуль.
Таким образом, в версии языка 3.8 появилось немало нового. Но большая часть информации, которая приводится выше, описывает не новые функции. Ведь уже появилась версия 3.9, и к моменту прочтения вами этой статьи, возможно, и новые версии. Тем не менее знать особенности каждой из версий полезно для понимания того, что доступно при той или иной версии языка. Например, если на офисном компьютере установлена устаревшая версия языка, то можно понимать, каких возможностей нет.