Что нового в Python 3.11
Изменения в Python 3.11 включают:
- оптимизацию производительности с добавлением изменений, связанных с ускорением и inline-развёртыванием вызова функций, применением быстрых интерпретаторов типовых операций (x+x, x*x, x-x, a[i], a[i] = z, f(arg) C(arg), o.method(), o.attr = z, *seq), а также оптимизацией в рамках проектов Cinder и HotPy. Разработчики обещают прирост скорости выполнения кода на 10-60%. В среднем производительность при прохождении тестового набора pyperformance увеличилась на 25%;
- переработанный механизм кэширования байткода, что позволило сократить время запуска интерпретатора на 10-15%. Объекты с кодом и байткод статически размещаются интерпретатором, чтобы исключить стадии демаршалинга извлечённого из кэша байткода и преобразования объектов с кодом для размещения в динамической памяти;
- вывод информации о выражении при отображении трассировки вызовов в диагностических сообщениях. Расширенную информацию о трассировке также можно получить через API и использовать для сопоставления отдельных инструкций байткода с конкретной позицией в исходном коде, используя метод codeobject.co_positions() или функцию C API PyCode_Addr2Location(). Это упрощает отладку проблем, связанных с вложенными объектами словарей, множественными вызовами функций и сложными арифметическими выражениями;
- поддержку групп исключений, дающих программе возможность генерировать и обрабатывать сразу несколько разных исключений одновременно. Для группировки нескольких исключений и их совместного вызова предложены новые типы ExceptionGroup и BaseExceptionGroup, а для выделения отдельных исключений из группы добавлено выражение “except*”;
- добавление метода add_note() в класс BaseException для прикрепления текстового примечания к исключению;
- добавление типа Self, представляющего текущий закрытый класс, для аннотирования методов, возвращающих экземпляр своего класса, более простым путём;
- добавление специального типа LiteralString, который может включать только строковые литералы, совместимые с типом LiteralString. Тип можно использовать для ограничения передачи функциям строковых аргументов, где произвольная подстановка частей строк может привести к уязвимостям;
- добавление TypeVarTuple, охватывающего произвольное число типов;
- включение модуля tomllib с функциями для разбора формата TOML в стандартную библиотеку;
- возможность пометки отдельных элементов типизованных словарей (TypedDict) метками Required и NotRequired для определения обязательных и необязательных полей;
- добавление класса TaskGroup в модуль asyncio с реализацией асинхронного контекстного менеджера, ожидающего завершения группы задач. Добавление задач в группу осуществляется при помощи метода create_task();
- добавление декоратора классов, методов и функций @dataclass_transform, при указании которого система проверки статических типов трактует объект, как при использовании декоратора @dataclasses.dataclass;
- добавление возможности использования атомарной группировки ((?>…)) и possessive-квантификаторов (*+, ++, ?+, {m,n}+) в регулярных выражениях;
- добавление опции командной строки “-P” и переменной окружения PYTHONSAFEPATH для отключения автоматического прикрепления к sys.path потенциально небезопасных файловых путей;
- улучшение утилиты py.exe для платформы Windows, в которой реализована поддержка синтаксиса “-V:<company>/<tag>” в дополнение к “-<major>.<minor>”;
- преобразование многих макросов в C API в обычные или статические inline-функции;
- удаление модулей uu, cgi, pipes, crypt, aifc, chunk, msilib, telnetlib, audioop, nis, sndhdr, imghdr, nntplib, spwd, xdrlib, cgitb, mailcap, ossaudiodev и sunau. Удаление функции PyUnicode_Encode*.
@python_job_interview – практика на Python в нашем канале.
Началось альфа-тестирование ветки Python 3.12. Она будет находиться на стадии альфа-выпусков в течение семи месяцев. Затем ещё три месяца будет проводиться тестирование бета-версий с исправлением ошибок.
Разберем подробно самые интересные улучшения
PEP 657: локатор трассировки ошибок
Раньше, до Python 3.11, при вызове исключения в трассировке ошибок содержалась лишь строка с описанием ошибки. Например:
x, y, z = 1, 2, 0
a, b, c = 3, 4, 5
result = (x / y / z) * (a / b / c)
В этом коде выдается ошибка, потому что при делении X/Y на Z
получается 0.
Это сообщение об ошибке неинформативно: неизвестно, какой частью кода ошибка вызвана.
В Python 3.11 вы увидите:
С локатором ошибок ~~^~~
выясняется первопричина: Y или Z равен нулю. В коде посложнее эти аннотированные трассировки мощнее.
PEP 673: тип self
Подсказки типа. Чтобы сослаться на сам текущий класс, раньше приходилось явно определять переменную типа:
В версии 3.11 на сам инкапсулирующий класс ссылается тип Self
и определять переменную типа не нужно:
Доработан асинхронный менеджер контекста {asyncio}
При асинхронном программировании код выполняется поэтапно. Чтобы не ждать завершения этапа до перехода к следующему, в Python используется модуль {asyncio}
.
Создаем асинхронные задачи, ждем запуска каждой и собираем их с помощью asyncio.gather()
:
## Задачи: [start_time, duration]errandsDict = {
'Grocery Shopping': [11, 2],
'Return Packages': [9, 1],
'Pick Up Kids': [6, 1],
}
async def errands_log(task, start_time, time_to_finish):
await asyncio.sleep(start_time)
print(f"({task}) starting at {start_time}am")
await asyncio.sleep(time_to_finish)
print(f"({task}) done at {start_time+time_to_finish}am\n ======;")
## Асинхронные задачи
async def run_errands():
errands = []
for errand, (start_time, time_to_finish) in errandsDict.items():
errands.append(errands_log(errand, start_time, time_to_finish))
## Сбор всей информации после запуска
await asyncio.gather(*errands)
asyncio.run(run_errands())
При запуске в терминале получаем:
Но отслеживать список задач вручную и затем собирать их с asyncio.gather
затруднительно. В Python 3.11 появилась новая функция/класс TaskGroup()
:
## With asyncio.TaskGroup
async def run_errands():
async with asyncio.TaskGroup() as tg:
for errand, (start_time, time_to_finish) in errandsDict.items():
tg.create_task(errands_log(errand,
start_time,
time_to_finish))
Она используется как контекстный менеджер, в котором содержится группа задач, и они все ожидаются им по завершении. Синтаксис здесь проще.
PEP 654: группа исключений
В версии 3.11 добавлена группа исключений — аналог функции «группировки» для их обработки. Это несколько исключений, обернутых в одно.
Когда ошибка приводит к вызову ExceptionGroup
, вызываются оба обернутых исключения, отображаемые в собственной области группы исключений:
Для обработки ошибок, обернутых в ExceptionGroup
, в Python 3.11 добавлено ключевое слово except*
:
Эта функция эффективнее в {asyncio} со множеством запускаемых вместе асинхронных задач.
PEP 678: настраиваемые примечания об исключениях
Другая новая функция для обработки ошибок — примечания об исключениях с добавлением (при помощи add_note
) настраиваемых сообщений:
PEP 659: увеличенная скорость выполнения
Благодаря инициативе Faster CPython Python 3.11 ожидается на 10–60% быстрее прошлых версий.
Усовершенствования стандартных библиотек
Есть несколько других улучшений качества стандартных библиотек. Прежде всего, в модуль math добавлены две долгожданные функции.Есть несколько других улучшений качества жизни стандартных библиотек. Прежде всего, в математический модуль добавлены две долгожданные функции.
>>> import math
>>> math.cbrt(9) # Find the cube-root of x
2.080083823051904
>>> math.cbrt(27)
3.0000000000000004
>>> math.exp2(5) # Raise 2 to the power of x
32.0
Тот факт, что Python потребовалось 28 лет, чтобы добавить функцию кубического корня, довольно удивителен, но, как говорится, лучше поздно, чем никогда.
В модуль дробей также добавлена новая функция, позволяющая создавать дроби из строк:
>>> from fractions import Fraction
>>> Fraction("22/7") # New in Python 3.11
Fraction(22, 7)
>>> Fraction(numerator=22, denominator=7)
Fraction(22, 7)
>>> Fraction("3e-4")
Fraction(3, 10000)
>>> Fraction("-73/41")
Fraction(-73, 41)
>>> Fraction(3.1415) # Find the closest approximation to the given float
Fraction(7074029114692207, 2251799813685248)
В итоге: переходить на Python 3.11 или нет?
Не обновляйте эксплуатационную среду, если у используемых в ваших проектах библиотек нет совместимости с Python 3.11.
Проверить это рекомендую в Google colab. Чтобы перейти на Python 3.11, запустите:
!sudo apt-get update -y
!sudo apt-get install python3.11
!sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 1
!sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 2
Мы рассмотрели самые интересные новые функции, все улучшения и изменения смотрите в официальной документации к выпуску.