В ответ на комментарий Вая вот одно забавное решение, которое я нашел. Прежде всего, чтобы еще раз объяснить, что он делает, предположим, что у вас есть следующий код:
definitions = Structure()
definitions.add_definition('f[x]', 'x*2')
definitions.add_definition('f[z]', 'some_function(z)')
definitions.add_definition('g.i', 'some_object[i].method(param=value)')
, где добавление определений подразумевает разбор левой и правой сторон и выполнение других неприятных вещей. Теперь один (не обязательно хороший, но, безусловно, веселый) подход позволил бы написать приведенный выше код следующим образом:
@my_dsl
def definitions():
f[x] = x*2
f[z] = some_function(z)
g.i = some_object[i].method(param=value)
и пусть Python сделает большую часть разбора под капотом.
Идея основана на простом утверждении exec <code> in <environment>
, упомянутом Яном, с одним хакерским дополнением. А именно, байт-код функции должен быть слегка изменен, и все локальные операции доступа к переменным (LOAD_FAST) переключаются на доступ к переменным из среды (LOAD_NAME).
Проще показать, чем объяснить: http://fouryears.eu/wp-content/uploads/pydsl/
Существуют различные приемы, которые вы можете сделать, чтобы сделать это практичным. Например, в коде, представленном по ссылке выше, вы не можете использовать встроенные функции и языковые конструкции, такие как for, и операторы if внутри функции @my_dsl. Однако вы можете заставить их работать, добавив больше поведения в класс Env.
Обновление . Здесь - более подробное объяснение того же самого.