Я хочу взломать интерпретатор 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)
Ответ 6
Проверьте модуль дизассемблера, найденный здесь:
http://docs.python.org/library/dis.html