Как читать байт-код python?

Мне сложно понять байт-код Python и его модуль dis.

import dis
def func():
   x = 1
dis.dis(func)

Приведенный выше код при вводе в интерпретатор выводит следующий результат:

    0 LOAD_CONST                  1(1)
    3 STORE_FAST                  0(x)
    6 LOAD_CONST                  0(NONE)
    9 RETURN_VALUE

например:.

В чем смысл LOAD_CONST, STORE_FAST и чисел типа 0, 3, 6 и 9?

Особый ресурс, в котором я могу найти эту информацию, будет высоко оценен.

Ответы

Ответ 1

Цифры перед байт-кодами являются смещениями в исходные двоичные байт-коды:

>>> func.__code__.co_code
'd\x01\x00}\x00\x00d\x00\x00S'

Некоторые байт-коды содержат дополнительную информацию (аргументы), которые влияют на то, как работает каждый байт-код, смещение указывает вам, в какой позиции в байтовом потоке был найден байт-код.

Байт-код LOAD_CONST (ASCII d, hex 64) сопровождается двумя дополнительными байтами, кодирующими ссылку на константу, связанную с байт-кодом, например. В результате код операции STORE_FAST (ASCII }, hex 7D) находится в индексе 3.

Документация модуля dis указывает, что означает каждая инструкция. Для LOAD_CONST говорится:

Вставляет co_consts[consti] в стек.

который ссылается на структуру co_consts, которая всегда присутствует с кодовым объектом; компилятор конструирует, что:

>>> func.__code__.co_consts
(None, 1)

Код операции загружает индекс 1 из этой структуры (01 00 байтов в кодировке байт-кода 1), и dis просмотрел это для вас; это значение 1.

Следующая инструкция STORE_FAST описана как:

Сохраняет TOS в локальный co_varnames[var_num].

Здесь TOS означает Top Of Stack; обратите внимание, что LOAD_CONST просто что-то вложил в стек, значение 1. co_varnames - другая структура; он ссылается на имена локальных переменных, индекс ссылок на код операции 0:

>>> func.__code__.co_varnames
('x',)

dis тоже выглядел, и имя, которое вы использовали в вашем коде, x. Таким образом, этот код операции хранит 1 в x.

Другой LOAD_CONST загружает None в стек из индекса 0, а затем RETURN_VALUE:

Возвращает с TOS вызывающему абоненту функции.

поэтому эта инструкция берет верхнюю часть стека (с константой None) и возвращается из этого кодового блока. None - это возвращаемое по умолчанию значение для функций без явного выражения return.

Вы опустили что-то из вывода dis, номера строк:

>>> dis.dis(func)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (x)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        

Обратите внимание на 2 в первой строке; что номер строки в исходном источнике, который содержит код Python, который использовался для этих инструкций. У объектов кода Python есть атрибуты co_lnotab и co_firstlineno, которые позволяют отображать байт-коды обратно на номера строк в исходном источнике. dis делает это для вас при демонстрации разборки.