В версии Python 3.11 среди прочего был представлен механизм специализированного адаптивного интерпретатора. Звучит сложно, но на самом деле все довольно понятно.
Bytecode
В процессе исполнения Python код преобразуется в так называемый байт-код - некоторое промежуточное представление между понятным нам кодом, и непонятным нам машинным кодом.
Python предоставляет удобный инструмент dis, позволяющий посмотреть как
исходный Python код будет преобразован в байт-код. Например, возьмем следующий
Python код:
def add(x: float, y: float) -> float:
    z = x + y
    return zМы можем посмотреть его байт-код представление выполнив следующие команды:
import dis
dis.dis(add, adaptive=True)Получим следующий вывод:
  4           0 RESUME                   0
  5           2 LOAD_FAST__LOAD_FAST     0 (x)
              4 LOAD_FAST                1 (y)
              6 BINARY_OP                0 (+)
             10 STORE_FAST__LOAD_FAST    2 (z)
  6          12 LOAD_FAST                2 (z)
             14 RETURN_VALUEСосредоточимся на одном конкретном блоке этого байт-кода:
6 BINARY_OP                0 (+)Объясняя простым языком, BINARY_OP 0 (+) берет два числа и складывает их.
Оптимизация “горячего” кода
Теперь, когда мы немного разобрались с байт-кодом, поговорим наконец об оптимизациях, которые были представлены в Python 3.11 в рамках специализированного адаптивного интерпретатора. Новые оптимизации нацелены на ускорение так называемого “горячего” кода - то есть участков кода, которые выполняются относительно часто.
Суть оптимизаций заключается в самом названии нового подхода: “специализированного” и “адаптивного”. Под этими словами подразумевается что инструкции байт-кода способны адаптироваться согласно тому как и на каких типах они используются, подстраиваясь под конкретные сценарии работы.
Рассмотрим на примере нашей функции add и в частности оператора сложения,
BINARY_OP 0 (+). Если мы N раз вызовем нашу функцию с аргументами типа float
и потом посмотрим на вывод байт-кода через dis.dis с флагом adaptive=True,
то увидим что инструкция BINARY_OP превратилась в BINARY_OP_ADD_FLOAT -
специализированную функцию, которая оптимизирована конкретно для сложения двух
чисел типа float:
import dis
def add(x: float, y: float) -> float:
    z = x + y
    return z
for _ in range(7):
    add(10.0, 10.2)
dis.dis(add, adaptive=True)
#   4           0 RESUME                   0
#   5           2 LOAD_FAST__LOAD_FAST     0 (x)
#               4 LOAD_FAST                1 (y)
#               6 BINARY_OP_ADD_FLOAT      0 (+)
#              10 STORE_FAST__LOAD_FAST    2 (z)
#   6          12 LOAD_FAST                2 (z)
#              14 RETURN_VALUEПочитать подробнее об этих оптимизациях можно в документе PEP 659.
Также, очень рекомендую к просмотру доклад Talks - Brandt Bucher: Inside CPython 3.11’s new specializing, adaptive interpreter.