Новые возможности, которые могут появиться в Python 3.8

Разбираем существующие PEP, представленные для версии 3.8. В июне текущего года мы узнаем, какие из них точно будут реализованы в Python 3.8.

Упрощение последовательности запуска CPython

Исследования показали, что большую часть времени запуска Python занимают операции ввода-вывода. PEP 432 объясняет четкую стратегию разделения процесса запуска на этапы. Идея состоит в том, что при запуске Python из командной строки или через WSGI-процесс происходила одна и та же последовательность инициализации, независимо от того, нужно запустить модульные тесты, поработать в REPL, выполнить произвольную функцию или предварительно скомпилированный скрипт.

Запуск интерпретатора предлагается разделить на три четко определенных и независимо настраиваемых этапа:

  1. Предварительная настройка времени выполнения ядра Python:

    • настройка управления памятью;
    • определение кодировок, используемых для системных интерфейсов.
  2. Инициализация времени выполнения ядра Python:

    • обеспечение готовности API на Си к использованию;
    • обеспечение доступности встроенных и замороженных модулей.
  3. Конфигурация основного интерпретатора:

    • обеспечение доступности внешних модулей.

Субинтерпретаторы в стандартной библиотеке

PEP 554 предлагает новый модуль стандартной библиотеки — interpreters. Он предоставит высокоуровневый интерфейс для субинтерпретаторов и обертку для новых низкоуровневых интерпретаторов. Это позволит изолировать код с меньшими издержками.

import interpreters
interp = interpreters.create()
print('before')
interp.run('print("during")')
print('after')

PEP 554 также предлагает расширить существующие API-интерфейсы, чтобы обеспечить наилучший обмен данными между интерпретаторами.

Сначала будут поддерживаться только следующие типы:

  • None
  • bytes
  • str
  • int
  • PEP 3118 buffer objects (через send_buffer())
  • PEP 554 channels

Поддержка None в операторах

PEP 505 предлагает три оператора с поддержкой None, подобно другим языкам.

Объединение по None (??)

text = val ?? "hello"

вместо:

if val is None:
    text = "hello"
else: 
    text = val

Доступ к атрибутам с поддержкой None (?.)

fruit = val.fruit?.name()

вместо:

if val.fruit is not None:
    fruit = val.fruit.name()
else:
    pass  

Индексация с поддержкой None (?[])

values = get_values()  # может иметь тип `list` или `None`
first = values?[0]

Поддержка переменных контекста для генераторов

PEP 567 (включен в Python 3.7) представил переменные контекста, которые прекрасно работают в многопоточной среде.

PEP 568 добавляет поддержку переменных контекста для генераторов. Важная новость для тех, кто работает с asyncio и планирует использовать генераторы.

Доступ к состоянию модуля из методов расширений на Си

PEP 573 предлагает добавить способ доступа к контексту для методов расширения CPython, такому как состояние модулей, в которых они определены.

Новые функции:

  • PyType_GetModule
  • PyType_DefiningTypeFromSlotFunc
  • PyType_GetModuleState
  • PyErr_PrepareImmutableException

Оператор присваивания

buf = inputfile.read(bufsize)
while buf:
    outputfile.write(buf)
    buf = inputfile.read(bufsize)

с PEP 572 можно будет заменить на:

while buf := inputfile.read(bufsize):
    outputfile.write(buf)

См. также «Python 3.8: почему в конструкции with… as не стоит as заменять оператором присваивания?».

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

PEP 576 предлагает расширить классы для встроенных функций и методов, чтобы они были больше похоже на функции Python. В частности, встроенные функции и методы получат доступ к модулю, в котором они объявлены, а встроенные методы получат доступ к классу, к которому они принадлежат.

Если вы пишете все приложение на Python и оптимизируете важные места с помощью Си (Cython), у вас есть 2 варианта:

  1. Использовать встроенные функции CPython, такие как len, print и т. д. Это предпочтительный вариант, но он имеет недостатки, если говорить о данных, к которым вы можете получить доступ в модуле (у вас их нет в случае реализации на Python).

  2. Создать собственную версии встроенных функций len, print и т. д., что, как правило, является плохой идеей.

Этот PEP подразумевает два изменения в API на Си:

  1. Добавлена ​​новая функция PyBuiltinFunction_New() для создания встроенных функций.

  2. PyCFunction_NewEx() и PyCFunction_New() устарели и будут возвращать, если возможно, PyBuiltinFunction, в противном случае builtin_function_or_method.

PEP 576 также предлагает новый встроенный класс builtin_function.

PEP 573 предлагает расширить API, к которому методы расширения, написанные на Си, имеют доступ, позволяя им видеть состояние модуля без необходимости вызывать дорогостоящую операцию PyState_FindModule. Реализация в основном полезна для Cython.

PEP 580 относится к разработке типов расширений из встроенных экземпляров buildin_function_or_method, method_descriptor, method и function y. Ни один из этих классов не является подклассом. Таким образом, любые оптимизации, основанные на предположениях о методе, встроенных функциях и т. д., нельзя выполнить.

PEP 573 предлагает заменить проверки для builtin_function_or_method и method_descriptor новым протоколом «C Call». Использование этого протокола означает, что разработанные пользователем типы расширений получат те же преимущества оптимизации, что и встроенные, такие как новый LOAD_METHOD, работающий на 20% быстрее (добавлен в Python 3.7).

Хуки для аудита Python во время исполнения

PEP 578 предлагает добавить хуки во время выполнения CPython, они могут быть полезны при разработке ПО в сфере безопасности, отладки и профилирования.

# Add an auditing hook
sys.addaudithook(hook: Callable[[str, tuple]])

# Raise an event with all auditing hooks
sys.audit(str, *args)

Среди предлагаемых событий — exec, import, compile и object.__setattr__. PEP дает рекомендации по основным низкоуровневым хукам, таким как выполнение объектов кода, но также и по высокоуровневым хукам, таким как открытие сетевых сокетов и вызов URL-адресов.

Хуки будут реализовывать ответы на события, типичными ответами будут регистрация события, прерывание операции с исключением или немедленное завершение процесса путем системного вызова exit.