Вопрос

Предположим, мне необходимо создать собственные маленькие DSL, которые будут использовать Python для описания определенной структуры данных. Например, я хотел бы иметь возможность написать что-то вроде

f(x) = some_stuff(a,b,c)

И иметь Python, вместо того, чтобы жаловаться на необъявленные идентификаторы или попытки вызвать функцию umy_Stuff, преобразуйте его в буквальное выражение для моего дополнительного удобства.

Для этого можно получить разумное приближение, создавая класс с должным образом переопределенным __getattr__ и __setattr__ Методы и используйте его следующим образом:

e = Expression()
e.f[e.x] = e.some_stuff(e.a, e.b, e.c)

Хотя было бы круто, если бы можно было избавиться от раздражающего «е». префиксы и, возможно, даже избежать использования []. Поэтому мне было интересно, возможно ли как-то временно «переопределить» глобальные поиски и заданиями? В соответствующем примечании, возможно, есть хорошие пакеты для легко достижения таких «цитирующих» функциональности для выражений Python?

Это было полезно?

Решение

Я не уверен, что это хорошая идея, но я думал, что попробовать. Отказ Подвести итоги:

class PermissiveDict(dict):
    default = None

    def __getitem__(self, item):
        try:
            return dict.__getitem__(self, item)
        except KeyError:
            return self.default

def exec_with_default(code, default=None):
    ns = PermissiveDict()
    ns.default = default
    exec code in ns
    return ns

Другие советы

Возможно, вы захотите взглянуть на ast или parser Модули включены в Python в анализ, доступ и преобразовать абстрактное синтаксическое дерево (или дерево разбора, соответственно) входного кода. Насколько я знаю, Мудрома математическая система, написанный в Python, имеет аналогичный сорт прекомпилеров.

В ответ на комментарий WAI вот одно забавное решение, которое я нашел. Прежде всего, объяснить еще раз, что он делает, предположим, что у вас есть следующий код:

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)')

Где добавление определений подразумевает расстановку левых сторон и правые стороны и выполняя другие уродливые вещи. Теперь один (не обязательно хороший, но, безусловно, Fun) подход здесь позволит написать вышеуказанный код следующим образом:

@my_dsl
def definitions():
    f[x] = x*2
    f[z] = some_function(z)
    g.i  = some_object[i].method(param=value)

И у Питона делают большую часть расставания под капотом. Идея основана на простом exec <code> in <environment> Заявление, упомянутое IAN, с одним хакерским дополнением. А именно, Bytecode функции должен быть немного настраиваться, и все локальные операции доступных доступных доступа (Load_fast) перешли на переменную доступ от среды (Load_name).

Это легче показано, чем объяснено: http://fouryears.eu/wp-content/uploads/pydsl/

Есть различные трюки, которые вы можете сделать, чтобы сделать его практичным. Например, в указанном на ссылке выше, вы не можете использовать встроенные функции и языковые конструкции, такие как для циклов, и если выступления в функции @my_dsl. Однако вы можете сделать эти работы, добавив больше поведения в класс Env.

Обновлять. Здесь немного более глубоко объяснение того же.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top