Опубликован: 22.12.2005 | Доступ: свободный | Студентов: 16813 / 518 | Оценка: 4.18 / 3.71 | Длительность: 16:16:00
ISBN: 978-5-9556-0109-0
Лекция 14:

Устройство интерпретатора языка Python

< Лекция 13 || Лекция 14: 12345678

Получение байт-кода

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

import parser

            prg = """print 2*2"""
            ast = parser.suite(prg)
            code = ast.compile('filename.py')
            exec code

            prg = """2*2"""
            ast = parser.expr(prg)
            code = ast.compile('filename1.py')
            print eval(code)

Функция parser.suite() (или parser.expr() ) возвращает AST-объект (дерево синтаксического анализа), которое методом compile() компилируется в Python байт-код и сохраняется в кодовом объекте code. Теперь этот код можно выполнить (или, в случае выражения - вычислить) с помощью оператора exec (или функции eval() ).

Здесь необходимо заметить, что недавно в Python появился пакет compiler, который объединяет модули для работы анализа исходного кода на Python и генерации кода. В данной лекции он не рассматривается, но те, кто хочет глубже изучить эти процессы, может обратиться к документации по Python.

Изучение байт-кода

Для изучения байт-кода Python-программы можно использовать модуль dis (сокращение от "дизассемблер"), который содержит функции, позволяющие увидеть байт-код в мнемоническом виде. Следующий пример иллюстрирует эту возможность:

>>> def f():
            ...   print 2*2
            ...
            >>> dis.dis(f)
              2           0 LOAD_CONST               1 (2)
                          3 LOAD_CONST               1 (2)
                          6 BINARY_MULTIPLY
                          7 PRINT_ITEM
                          8 PRINT_NEWLINE
                          9 LOAD_CONST               0 (None)
                         12 RETURN_VALUE

Определяется функция f(), которая должна вычислить и напечатать значение выражения 2*2. Функция dis() модуля dis выводит код функции f() в виде некого "ассемблера", в котором байт-код Python представлен мнемоническими именами. Следует заметить, что при интерпретации используется стек, поэтому LOAD_CONST кладет значение на вершину стека, а BINARY_MULTIPLY берет со стека два значения и помещает на стек результат их перемножения. Функция без оператора return возвращает значение None. Как и в случае с кодами для микропроцессора, некоторые байт-коды принимают параметры.

Мнемонические имена можно увидеть в списке dis.opname (ниже печатаются только задействованные имена):

>>> import dis
            >>> [n for n in dis.opname if n[0] != "<"]
            ['STOP_CODE', 'POP_TOP', 'ROT_TWO', 'ROT_THREE', 'DUP_TOP', 'ROT_FOUR',
            'NOP', 'UNARY_POSITIVE', 'UNARY_NEGATIVE', 'UNARY_NOT', 'UNARY_CONVERT',
            'UNARY_INVERT', 'LIST_APPEND', 'BINARY_POWER', 'BINARY_MULTIPLY',
            'BINARY_DIVIDE', 'BINARY_MODULO', 'BINARY_ADD', 'BINARY_SUBTRACT',
            'BINARY_SUBSCR', 'BINARY_FLOOR_DIVIDE', 'BINARY_TRUE_DIVIDE',
            'INPLACE_FLOOR_DIVIDE', 'INPLACE_TRUE_DIVIDE', 'SLICE+0', 'SLICE+1',
            'SLICE+2', 'SLICE+3', 'STORE_SLICE+0', 'STORE_SLICE+1', 'STORE_SLICE+2',
            'STORE_SLICE+3', 'DELETE_SLICE+0', 'DELETE_SLICE+1', 'DELETE_SLICE+2',
            'DELETE_SLICE+3', 'INPLACE_ADD', 'INPLACE_SUBTRACT', 'INPLACE_MULTIPLY',
            'INPLACE_DIVIDE', 'INPLACE_MODULO', 'STORE_SUBSCR', 'DELETE_SUBSCR',
            'BINARY_LSHIFT', 'BINARY_RSHIFT', 'BINARY_AND', 'BINARY_XOR', 'BINARY_OR',
            'INPLACE_POWER', 'GET_ITER', 'PRINT_EXPR', 'PRINT_ITEM', 'PRINT_NEWLINE',
            'PRINT_ITEM_TO', 'PRINT_NEWLINE_TO', 'INPLACE_LSHIFT', 'INPLACE_RSHIFT',
            'INPLACE_AND', 'INPLACE_XOR', 'INPLACE_OR', 'BREAK_LOOP', 'LOAD_LOCALS',
            'RETURN_VALUE', 'IMPORT_STAR', 'EXEC_STMT', 'YIELD_VALUE', 'POP_BLOCK',
            'END_FINALLY', 'BUILD_CLASS', 'STORE_NAME', 'DELETE_NAME',
            'UNPACK_SEQUENCE', 'FOR_ITER', 'STORE_ATTR', 'DELETE_ATTR', 'STORE_GLOBAL',
            'DELETE_GLOBAL', 'DUP_TOPX', 'LOAD_CONST', 'LOAD_NAME', 'BUILD_TUPLE',
            'BUILD_LIST', 'BUILD_MAP', 'LOAD_ATTR', 'COMPARE_OP', 'IMPORT_NAME',
            'IMPORT_FROM', 'JUMP_FORWARD', 'JUMP_IF_FALSE', 'JUMP_IF_TRUE',
            'JUMP_ABSOLUTE', 'LOAD_GLOBAL', 'CONTINUE_LOOP', 'SETUP_LOOP',
            'SETUP_EXCEPT', 'SETUP_FINALLY', 'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST',
            'RAISE_VARARGS', 'CALL_FUNCTION', 'MAKE_FUNCTION', 'BUILD_SLICE',
            'MAKE_CLOSURE', 'LOAD_CLOSURE', 'LOAD_DEREF', 'STORE_DEREF',
            'CALL_FUNCTION_VAR', 'CALL_FUNCTION_KW', 'CALL_FUNCTION_VAR_KW',
            'EXTENDED_ARG']

Легко догадаться, что LOAD означает загрузку значения в стек, STORE - выгрузку, PRINT - печать, BINARY - бинарную операцию и т.п.

< Лекция 13 || Лекция 14: 12345678
Андрей Егоров
Андрей Егоров

def bin(n):

"""Цифры двоичного представления натурального числа """

if n == 0:

   return []

n, d = divmod(n, 2)

return bin(n) + [d]

print bin(69)

Что значит здесь return[] ? Возвращает список? Непонятно какой список? Откуда он? 

 

 

Асмик Гаряка
Асмик Гаряка

Почему при вычислении рейтинга не учитывается уровень, как описано? Для всех курсов У=1, хотя для Специалист должно быть 2.

Максим Иванов
Максим Иванов
Украина, Киев
Алеся Шевченко
Алеся Шевченко
Россия, г. Рубцовск