Написать пост

Фичи из свежих релизов Python

Аватарка пользователя Елена Капаца

Рассказываем, какие новые функции появились в свежих релизах Python. Среди них прокачанный трейсинг ошибок и чтение TOML-конфигов.

Обложка поста Фичи из свежих релизов Python

Не каждый день питонисты сталкиваются со всеми апгрейдами языка, и расшифровка релиз-полотна точно поможет улучшить стиль и приблизить его к стандартам PEP и Zen of Python.

Прокачанный трейсинг ошибок

Классической проблемой новичка становится отладка программы: по трейсбеку (описанию) определить, в чем дело, бывает весьма затруднительно:

			def inverse(number):
    return 1 / number

print(inverse(0))
		

Теперь для указания на конкретный объект, вызвавший ошибку, используется строка с несколькими ^ (символ называется “циркумфлекс”). В сниппете выше мы просим поделить на ноль, и конечно, это вызывает ошибку:

			Traceback (most recent call last):
  File "/home/realpython/inverse.py", line 6, in <module>
    print(inverse(0))
          ^^^^^^^^^^
  File "/home/realpython/inverse.py", line 4, in inverse
    return 1 / number
           ~~^~~~~~~~
ZeroDivisionError: division by zero
		

Не скажу, что это снимает 99% нагрузки, но все же чуть лучше “подводит” нас к сути.

Улучшенный синтаксис параллельных процессов

Раньше мы вручную отслеживали все свои задачи в списке, прежде чем передать их в collect():

			tasks = [asyncio.create_task(run_some_task(param)) for param in params]
await asyncio.gather(*tasks)
		

Теперь используем контекстный менеджер:

			async with asyncio.TaskGroup() as tg:
    for param in params:
        tg.create_task(run_some_task(param))
		

Ускоренный импорт библиотек

Если запустить следующий скрипт в Python версий 2.x.x и 3.11.4, то вы заметите солидный прирост в скорости подключения инструментов. В забавной мини-программе ниже выводится скорость импорта библиотек _io, marshal и проч., да еще и ASCII-графика с питончиком:

			import sys

message = " ".join(sys.argv[1:])
bubble_length = len(message) + 2
print(
    rf"""
       {"_" * bubble_length}
      ( {message} )
       {"‾" * bubble_length}
        \
         \    __
          \  [oo]
             (__)\
               λ \\
                 _\\__
                (_____)_
               (________)Oo°"""
)
		
			$ python -X importtime -S snakesay.py Imports are faster!
import time: self [us] | cumulative | imported package
import time:       283 |        283 |   _io
import time:        56 |         56 |   marshal
import time:       647 |        647 |   posix
import time:       587 |       1573 | _frozen_importlib_external
import time:       167 |        167 |   time
import time:       191 |        358 | zipimport
import time:        90 |         90 |     _codecs
import time:       561 |        651 |   codecs
import time:       825 |        825 |   encodings.aliases
import time:      1136 |       2611 | encodings
import time:       417 |        417 | encodings.utf_8
import time:       174 |        174 | _signal
import time:        56 |         56 |     _abc
import time:       251 |        306 |   abc
import time:       310 |        616 | io
       _____________________
      ( Imports are faster! )
       ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
        \
         \    __
          \  [oo]
             (__)\
               λ \\
                 _\\__
                (_____)_
               (________)Oo°
		

Группы исключений

Теперь можно объединять ошибки некоторых видов в группу и обрабатывать их одинаково:

			>>> raise ExceptionGroup("twice", [TypeError("int"), ValueError(654)])
		

Интересно, насколько ускорится процесс разработки, если вываливать на питониста сразу все причины падения? В выводе ниже одновременно и ошибка типа, и ошибка некорректного значения.

			+ Exception Group Traceback (most recent call last):
  |   File "<stdin>", line 1, in <module>
  | ExceptionGroup: twice (2 sub-exceptions)
  +-+---------------- 1 ----------------
    | TypeError: int
    +---------------- 2 ----------------
    | ValueError: 654
    +------------------------------------
		

Обогащение деталей ошибки

Теперь разработчик вправе дополнить ошибку кастомной заметкой:

			err = ValueError(678)
err.add_note("Важная деталь, отличающая эту ошибку от остальных")
raise err
		

Фича становится восхитительно полезной, когда типов ошибок много:

			Traceback (most recent call last):
  ...
ValueError: 678
Важная деталь, отличающая эту ошибку от остальных
Python 3.11
		

Чтение TOML-конфигов

Этот формат стал популярен относительно недавно и даже претендует на замену JSON ввиду повышенной “человекочитаемости”:

Наконец, разработчики ЯП зарелизили встроенную библиотеку для чтения таких файлов:

			import tomllib

toml_str = """
python-version = "3.11.0"
release_date = "2022-10-22"
"""

data = tomllib.loads(toml_str)
print(data)  # {'python-version': '3.11.0', 'release_date': '2022-10-22'}
print(data['python-version'])  # 3.11.0
print(data['release_date'])  # 2022-10-22
		

Заключение

Некоторые практикующие питонисты, молящиеся на проработанность ЯП, такие нюансы ждали годами. Но новичку в них, на мой взгляд, может быть непросто разобраться. И еще сложнее читать оригинальное описание релиза.

Так что новеньким, стремящимся прокачать скилл, советую сначала изучить подборки вроде этой: “10 фишек Python, которые поднимут ваш скилл на новый уровень”.

Какие еще фичи свежих релизов вы используете? Поделитесь в комментариях.

Следите за новыми постами
Следите за новыми постами по любимым темам
905 открытий2К показов