Есть ли способ программно генерировать байт-код Python?

Я хочу взломать интерпретатор Python и попытаться создать небольшую DSL. Есть ли какой-нибудь модуль, где я могу сделать что-то вроде этого теоретического кода (похожего на деревья выражения LINQ)?

expression_tree = Function(
    Print(
        String('Hello world!')
    )
 )
compile_to_bytecode(expression_tree)

Или просто проще просто создать исходный код Python? Могло ли это упроститься с помощью C или SWIG или Cython?

Ответ 1

Работа с помощью ast и компиляция дерева в байт-код, как показывает другой ответ, вероятно, проще всего; генерировать источники и компилировать их почти так же хорошо.

Однако, чтобы изучить подходы более низкого уровня, проверьте ссылки из на этой странице; Я нашел byteplay особенно полезный (в настоящее время он не работает с 2.6 или 3. *, только 2,4 или 2,5, но я думаю, что исправление он для 2.6 должен быть простым, как в настоящее время обсуждается в его трекере). Я не использовал Фила Эби аналогично признанного BytecodeAssembler, но, учитывая репутацию автора, я уверен, что стоит проверить его!

Ответ 2

В Python 2.X вы обычно подходите к этому с помощью compiler module и его под-модуля ast (но обратите внимание, что этот модуль устарел с версии 2.6). В Python 3.X вы должны использовать только ast.

Оба предлагают функцию compile(), которая будет поступать из источника /AST в "объект кода, который может быть выполнен оператором exec или eval()."

Ответ 3

Легче сгенерировать код Python и запустить его. Если вы это сделаете, вы можете легко отладить его, так как есть реальный источник для отладки для отображения. См. Также статью Malte Borchs в июльском выпуске журнала Python, где он рассказывает об этом среди прочего.

Ответ 4

Фернандо Мейер недавно написал сообщение в блоге, в котором объясняется, как использовать директиву # coding, чтобы указать свои собственные расширения для Python. Пример (фактическое определение формата находится в pyspec.py и tokenizer.py):

# coding: pyspec

class Bow:
    def shot(self):
        print "got shot"

    def score(self):
        return 5

describe Bowling:
    it "should score 0 for gutter game":
        bowling = Bow()
        bowling.shot()
        assert that bowling.score.should_be(5)

Ответ 5

Обновление для Python3 - также очень интересный ассемблер zachariahreed/byteasm.

Собственно, единственный, кто работает для меня в Py3. Он имеет очень красивый и чистый API:

>>> import byteasm, dis
>>> b = byteasm.FunctionBuilder()
>>> b.add_positional_arg('x')
>>> b.emit_load_const('Hello!')
>>> b.emit_load_fast('x')
>>> b.emit_build_tuple(2)
>>> b.emit_return_value()
>>> f = b.make('f')
>>> f
<function f at 0xb7012a4c>
>>> dis.dis(f)
  1           0 LOAD_CONST               0 ('Hello!')
              3 LOAD_FAST                0 (x)
              6 BUILD_TUPLE              2
              9 RETURN_VALUE
>>> f(108)
('Hello!', 108)