Документация Python неофициальный перевод
Содержание страницы

30.12. dis – Дисассемблер байт-кода Pythondis – Disassembler for Python bytecode

Модуль dis поддерживает анализ CPython байт-кода путём его дизассемблирования. CPython байт-код, который этот модуль принимает на вход, определён в файле Include/opcode.h и используется компилятором и интерпретатором.

Особенность реализации CPython: Байт-код – деталь реализации интерпретатора CPython! Не гарантируется, что байт-код не будет добавлен, удалён или изменён в разных версиях Python. Не следует рассчитывать, что этот модуль будет работать в других виртуальных машинах Python или в других выпусках Python.

Пример: дана функция myfunc():

def myfunc(alist):
    return len(alist)

Для получения дизассемблированного кода myfunc() можно использовать следующую команду:

>>> dis.dis(myfunc)
  2           0 LOAD_GLOBAL              0 (len)
              3 LOAD_FAST                0 (alist)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE

(«2» – это номер строки).

Модуль dis определяет следующие функции и константы:

dis.dis(x=None)
Дизассемблирует объект x. x может обозначать модуль, класс, метод, функцию, объект кода, строку исходного кода или последовательность байтов сырого байт-кода. Для модуля дизассемблируются все функции. Для класса – все методы. Для объекта кода или последовательности сырого байт-кода выводится по одной строке на каждую инструкцию байт-кода. Строки сначала компилируются в объекты кода с помощью встроенной функции compile(), а затем дизассемблируются. Если объект не указан, функция дизассемблирует последнюю трассировку.
dis.distb(tb=None)
Дисассемблирует функцию, находящуюся на вершине стека traceback; если traceback не передан, используется последний. Указывается инструкция, вызвавшая исключение.
dis.disassemble(code, lasti=-1)
dis.disco(code, lasti=-1)

Дисассемблирует объект кода, указывая последнюю инструкцию, если передан lasti. Результат разбит на следующие столбцы:

  1. номер строки для первой инструкции каждой строки
  2. текущая инструкция, помечена как -->,
  3. инструкция с меткой, помечена >>,
  4. адрес инструкции,
  5. название кода операции,
  6. параметры операции и
  7. интерпретация параметров в скобках.

Интерпретация параметров распознаёт имена локальных и глобальных переменных, константные значения, цели переходов и операторы сравнения.

dis.findlinestarts(code)
Эта функция-генератор использует атрибуты co_firstlineno и co_lnotab объекта кода code для поиска смещений, соответствующих началам строк в исходном коде. Они генерируются в виде пар (offset, lineno).
dis.findlabels(code)
Определяет все смещения в объекте кода code, которые являются целями перехода, и\nвозвращает список этих смещений.
dis.opname
Последовательность имён операций, индексируемая с помощью байткода.
dis.opmap
Словарь, сопоставляющий имена операций с байткодами.
dis.cmp_op
Последовательность всех имён операций сравнения.
dis.hasconst
Последовательность байткодов, имеющих постоянный параметр.
dis.hasfree
Последовательность байткодов, обращающихся к свободной переменной.
dis.hasname
Последовательность байткодов, обращающихся к атрибуту по имени.
dis.hasjrel
Последовательность байткодов, имеющих относительную цель перехода.
dis.hasjabs
Последовательность байткодов, имеющих абсолютную цель перехода.
dis.haslocal
Последовательность байткодов, обращающихся к локальной переменной.
dis.hascompare
Последовательность байткодов логических операций.

30.12.1. Инструкции байткода PythonPython Bytecode Instructions

В настоящее время компилятор Python генерирует следующие инструкции байткода.

Общие инструкции

STOP_CODE
Указывает компилятору на конец кода, не используется интерпретатором.
NOP
Код, который ничего не делает. Используется в качестве заполнителя оптимизатором байт-кода.
POP_TOP
Удаляет элемент с вершины стека (TOS).
ROT_TWO
Меняет местами два верхних элемента стека.
ROT_THREE
Поднимает второй и третий элементы стека на одну позицию вверх, перемещает верхний вниз на третью позицию.
ROT_FOUR
Поднимает второй, третий и четвёртый элементы стека на одну позицию вверх, перемещает верхний элемент вниз на четвёртую позицию.
DUP_TOP
Дублирует ссылку на вершине стека.

Унарные операции

Унарные операции берут элемент с вершины стека, применяют операцию и помещают результат обратно на стек.

UNARY_POSITIVE
Реализует TOS = +TOS.
UNARY_NEGATIVE
Реализует TOS = -TOS.
UNARY_NOT
Реализует TOS = не TOS.
UNARY_INVERT
Реализует TOS = ~TOS.
GET_ITER
Реализует TOS = iter(TOS).

Бинарные операции

Бинарные операции удаляют из стека элемент с вершины (TOS) и второй сверху элемент стека (TOS1). Они выполняют операцию и помещают результат обратно в стек.

BINARY_POWER
Реализует TOS = TOS1 ** TOS.
BINARY_MULTIPLY
Реализует TOS = TOS1 * TOS.
BINARY_FLOOR_DIVIDE
Реализует TOS = TOS1 // TOS.
BINARY_TRUE_DIVIDE
Реализует TOS = TOS1 / TOS.
BINARY_MODULO
Реализует TOS = TOS1 % TOS.
BINARY_ADD
Реализует TOS = TOS1 + TOS.
BINARY_SUBTRACT
Реализует TOS = TOS1 - TOS.
BINARY_SUBSCR
Реализует TOS = TOS1[TOS].
BINARY_LSHIFT
Реализует TOS = TOS1 << TOS.
BINARY_RSHIFT
Реализует TOS = TOS1 >> TOS.
BINARY_AND
Реализует TOS = TOS1 & TOS.
BINARY_XOR
Реализует TOS = TOS1 ^ TOS.
BINARY_OR
Реализует TOS = TOS1 | TOS.

Операции на месте

Операции на месте аналогичны бинарным: они также удаляют TOS и TOS1 и помещают результат обратно в стек, но операция выполняется на месте, если TOS1 это поддерживает, и результирующий TOS может (но не обязан) быть исходным TOS1.

INPLACE_POWER
Реализует in-place: TOS = TOS1 ** TOS.
INPLACE_MULTIPLY
Реализует in-place: TOS = TOS1 * TOS.
INPLACE_FLOOR_DIVIDE
Реализует in-place: TOS = TOS1 // TOS.
INPLACE_TRUE_DIVIDE
Реализует in-place: TOS = TOS1 / TOS.
INPLACE_MODULO
Реализует in-place: TOS = TOS1 % TOS.
INPLACE_ADD
Реализует in-place: TOS = TOS1 + TOS.
INPLACE_SUBTRACT
Реализует in-place: TOS = TOS1 - TOS.
INPLACE_LSHIFT
Реализует in-place: TOS = TOS1 << TOS.
INPLACE_RSHIFT
Реализует in-place: TOS = TOS1 >> TOS.
INPLACE_AND
Реализует in-place: TOS = TOS1 & TOS.
INPLACE_XOR
Реализует in-place: TOS = TOS1 ^ TOS.
INPLACE_OR
Реализует in-place: TOS = TOS1 | TOS.
STORE_SUBSCR
Реализует TOS1[TOS] = TOS2.
DELETE_SUBSCR
Реализует del TOS1[TOS].

Прочие опкоды

PRINT_EXPR
Реализует оператор выражения для интерактивного режима. TOS удаляется из стека и выводится на печать. В неинтерактивном режиме оператор выражения завершается POP_STACK.
BREAK_LOOP
Завершает цикл при выполнении оператора break.
CONTINUE_LOOP(target)
Продолжает цикл при выполнении оператора continue. target – это адрес перехода (должен быть инструкцией FOR_ITER).
SET_ADD(i)
Вызывает set.add(TOS1[-i], TOS). Используется для реализации множественных включений (set comprehensions).
LIST_APPEND(i)
Вызывает list.append(TOS[-i], TOS). Используется для реализации списковых включений (list comprehensions).
MAP_ADD(i)
Вызывает dict.setitem(TOS1[-i], TOS, TOS1). Используется для реализации словарных включений (dict comprehensions).

Для всех инструкций SET_ADD, LIST_APPEND и MAP_ADD, после извлечения добавляемого значения или пары ключ/значение, объект-контейнер остаётся в стеке, чтобы его можно было использовать в следующих итерациях цикла.

RETURN_VALUE
Возвращает TOS вызывающей стороне функции.
YIELD_VALUE
Извлекает TOS и возвращает его из генератора.
IMPORT_STAR
Загружает все символы, не начинающиеся с '_', непосредственно из модуля TOS в локальное пространство имён. Модуль извлекается после загрузки всех имён. Этот опкод реализует from module import *.
POP_BLOCK
Удаляет один блок из стека блоков. Для каждого фрейма существует стек блоков, обозначающий вложенные циклы, операторы try и тому подобное.
POP_EXCEPT
Удаляет один блок из стека блоков. Извлечённый блок должен быть блоком обработчика исключений, который неявно создаётся при входе в обработчик except. Помимо извлечения лишних значений из стека фрейма, последние три извлечённых значения используются для восстановления состояния исключения.
END_FINALLY
Завершает блок finally. Интерпретатор запоминает, нужно ли повторно возбуждать исключение или функция возвращается, и продолжает со следующим внешним блоком.
LOAD_BUILD_CLASS
Помещает builtins.__build_class__() в стек. Позже она вызывается инструкцией CALL_FUNCTION для создания класса.
WITH_CLEANUP

Очищает стек при выходе из блока оператора with. TOS – это привязанный метод __exit__() менеджера контекста. Ниже TOS находятся 1–3 значения, указывающие, каким образом/почему был выполнен блок finally:

  • SECOND = None
  • (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval
  • SECOND = WHY_*; под ним нет retval
  • (SECOND, THIRD, FOURTH) = exc_info()

В последнем случае вызывается TOS(SECOND, THIRD, FOURTH), иначе TOS(None, None, None). Кроме того, TOS удаляется из стека.

Если стек представляет исключение, и вызов функции возвращает истинное значение, эта информация «зануляется» и заменяется одним значением WHY_SILENCED, чтобы предотвратить повторное возбуждение исключения инструкцией END_FINALLY. (Но нелокальные переходы все равно будут возобновлены.)

STORE_LOCALS
Извлекает TOS из стека и сохраняет его как f_locals текущего фрейма. Используется при построении класса.

Все следующие опкоды требуют аргументов. Аргумент занимает два байта, причём старший байт идёт последним.

STORE_NAME(namei)
Реализует name = TOS. namei – это индекс name в атрибуте co_names объекта кода. Компилятор старается использовать STORE_FAST или STORE_GLOBAL, если это возможно.
DELETE_NAME(namei)
Реализует del name, где namei – это индекс в атрибуте co_names объекта кода.
UNPACK_SEQUENCE(count)
Распаковывает TOS в count отдельных значений, которые помещаются в стек справа налево.
UNPACK_EX(counts)

Реализует присваивание с целевой переменной со звёздочкой: распаковывает итерируемый объект в TOS в отдельные значения, где общее количество значений может быть меньше количества элементов в итерируемом объекте: одно из новых значений будет списком всех оставшихся элементов.

Младший байт counts – это количество значений до спискового значения, а старший байт counts – количество значений после него. Результирующие значения помещаются в стек справа налево.

DUP_TOPX(count)
Дублирует count элементов, сохраняя их порядок. Из-за ограничений реализации count должен быть в диапазоне от 1 до 5 включительно.
STORE_ATTR(namei)
Реализует TOS.name = TOS1, где namei – это индекс имени в co_names.
DELETE_ATTR(namei)
Реализует del TOS.name, используя namei как индекс в co_names.
STORE_GLOBAL(namei)
Работает как STORE_NAME, но сохраняет имя как глобальное.
DELETE_GLOBAL(namei)
Работает как DELETE_NAME, но удаляет глобальное имя.
LOAD_CONST(consti)
Помещает co_consts[consti] в стек.
LOAD_NAME(namei)
Помещает значение, связанное с co_names[namei], в стек.
BUILD_TUPLE(count)
Создает кортеж, беря count элементов из стека, и помещает полученный кортеж обратно в стек.
BUILD_LIST(count)
Работает как BUILD_TUPLE, но создает список.
BUILD_SET(count)
Работает как BUILD_TUPLE, но создает множество.
BUILD_MAP(count)
Помещает новый объект словаря в стек. Словарь предварительно настраивается на хранение count записей.
LOAD_ATTR(namei)
Заменяет TOS на getattr(TOS, co_names[namei]).
COMPARE_OP(opname)
Выполняет булеву операцию. Имя операции можно найти в cmp_op[opname].
IMPORT_NAME(namei)
Импортирует модуль co_names[namei]. TOS и TOS1 извлекаются и предоставляют аргументы fromlist и level для __import__(). Объект модуля помещается в стек. Текущее пространство имен не затрагивается: для правильного оператора import последующая инструкция STORE_FAST изменяет пространство имен.
IMPORT_FROM(namei)
Загружает атрибут co_names[namei] из модуля, находящегося в TOS. Полученный объект помещается в стек, чтобы затем быть сохраненным инструкцией STORE_FAST.
JUMP_FORWARD(delta)
Увеличивает счётчик байт-кода на delta.
POP_JUMP_IF_TRUE(target)
Если TOS истинно, устанавливает счётчик байткода в target. TOS извлекается из стека.
POP_JUMP_IF_FALSE(target)
Если TOS ложно, устанавливает счётчик байткода в target. TOS извлекается из стека.
JUMP_IF_TRUE_OR_POP(target)
Если TOS истинно, устанавливает счетчик байткода в target и оставляет TOS в стеке. В противном случае (TOS ложно) TOS извлекается.
JUMP_IF_FALSE_OR_POP(target)
Если TOS ложен, устанавливает счетчик байт-кода в target и оставляет TOS на стеке. В противном случае (TOS истинен) TOS снимается со стека.
JUMP_ABSOLUTE(target)
Устанавливает счётчик байткода в target.
FOR_ITER(delta)
TOS – это итератор. Вызовите его метод __next__(). Если это возвращает новое значение, поместите его в стек (оставив итератор под ним). Если итератор сигнализирует, что он исчерпан, TOS извлекается, а счетчик байт-кода увеличивается на delta.
LOAD_GLOBAL(namei)
Загружает глобальную переменную с именем co_names[namei] в стек.
SETUP_LOOP(delta)
Помещает блок для цикла в стек блоков. Блок начинается с текущей инструкции и имеет размер delta байт.
SETUP_EXCEPT(delta)
Помещает блок try из конструкции try-except в стек блоков. delta указывает на первый блок except.
SETUP_FINALLY(delta)
Помещает блок try из конструкции try-except в стек блоков. delta указывает на блок finally.
STORE_MAP
Сохраняет пару ключ-значение в словаре. Снимает со стека ключ и значение, оставляя словарь в стеке.
LOAD_FAST(var_num)
Помещает ссылку на локальную переменную co_varnames[var_num] в стек.
STORE_FAST(var_num)
Сохраняет TOS в локальную переменную co_varnames[var_num].
DELETE_FAST(var_num)
Удаляет локальную переменную co_varnames[var_num].
LOAD_CLOSURE(i)
Помещает в стек ссылку на ячейку, содержащуюся в слоте i хранилища ячеек и свободных переменных. Имя переменной – co_cellvars[i], если i меньше длины co_cellvars. В противном случае – co_freevars[i - len(co_cellvars)].
LOAD_DEREF(i)
Загружает ячейку, содержащуюся в слоте i хранилища ячеек и свободных переменных. Помещает ссылку на объект, который содержит ячейка, в стек.
STORE_DEREF(i)
Сохраняет TOS в ячейку, содержащуюся в слоте i хранилища ячеек и свободных переменных.
RAISE_VARARGS(argc)
Вызывает исключение. argc указывает количество параметров оператора raise (от 0 до 3). Обработчик увидит объект traceback как TOS2, параметр как TOS1, а исключение как TOS.
CALL_FUNCTION(argc)
Вызывает функцию. Младший байт argc указывает количество позиционных параметров, старший байт – количество именованных параметров. В стеке опкод сначала находит именованные параметры. Для каждого именованного аргумента значение находится поверх ключа. Под именованными параметрами в стеке располагаются позиционные параметры, причем самый правый параметр – наверху. Под параметрами находится вызываемый объект функции. Снимает со стека все аргументы функции и саму функцию, затем помещает в стек возвращаемое значение.
MAKE_FUNCTION(argc)
Помещает новый объект функции в стек. TOS – это код, связанный с функцией. Объект функции определяется как имеющий argc параметров по умолчанию, которые находятся под TOS.
MAKE_CLOSURE(argc)
Создаёт новый объект функции, устанавливает его слот __closure__ и помещает его в стек. TOS – это код, связанный с функцией, TOS1 – кортеж содержащий ячейки для свободных переменных замыкания. Функция также имеет argc параметров по умолчанию, которые находятся под ячейками.
BUILD_SLICE(argc)

Помещает объект среза в стек. argc должен быть равен 2 или 3. Если он равен 2, помещается slice(TOS1, TOS); если 3 – slice(TOS2, TOS1, TOS). Подробнее см. встроенную функцию slice().

EXTENDED_ARG(ext)
Является префиксом для любого опкода, аргумент которого слишком велик, чтобы поместиться в стандартные два байта. ext содержит два дополнительных байта, которые вместе с аргументом последующего опкода образуют четырехбайтовый аргумент, причем ext является двумя старшими байтами.
CALL_FUNCTION_VAR(argc)
Вызывает функцию. argc интерпретируется так же, как в CALL_FUNCTION. Верхний элемент стека содержит список аргументов переменной длины, за которым следуют именованные и позиционные аргументы.
CALL_FUNCTION_KW(argc)
Вызывает функцию. argc интерпретируется так же, как в CALL_FUNCTION. Верхний элемент в стеке содержит словарь именованных аргументов, за которым следуют явные именованные и позиционные аргументы.
CALL_FUNCTION_VAR_KW(argc)
Вызывает функцию. argc интерпретируется так же, как в CALL_FUNCTION. Верхний элемент в стеке содержит словарь именованных аргументов, за которым следуют кортеж переменных аргументов, а затем явные именованные и позиционные аргументы.
HAVE_ARGUMENT
Это не совсем опкод. Он обозначает разделительную линию между опкодами, не принимающими аргументы < HAVE_ARGUMENT, и теми, которые принимают >= HAVE_ARGUMENT.