假设我需要创建自己的小型 DSL,它将使用 Python 来描述某种数据结构。例如。我希望能够写出类似的东西

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

并且使用 Python,不要抱怨未声明的标识符或尝试调用函数 some_stuff,而是将其转换为文字表达式以方便我使用。

通过创建一个正确重新定义的类,可以得到合理的近似值 __getattr____setattr__ 方法并使用如下:

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

但是,如果有可能摆脱烦人的“ E”,那将很酷。前缀,甚至可能避免使用[]。所以我想知道,是否有可能以某种方式暂时“重新定义”全局名称查找和分配?与此相关的是,也许有好的软件包可以轻松实现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

其他提示

您可能想看看包括在Python解析,获取和变换(分别或解析树,)所述输入代码的抽象语法树的astparser模块。据我所知,贤者数学系统,用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)')

添加定义意味着解析左侧和右侧以及做其他丑陋的事情。现在,这里的一种(不一定好,但肯定有趣)方法允许将上面的代码编写如下:

@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> 伊恩(Ian)提到的声明,并添加了一个黑客行为。也就是说,必须稍微调整函数的字节码,并将所有局部变量访问操作 (LOAD_FAST) 切换为来自环境的变量访问 (LOAD_NAME)。

显示比解释更容易: http://fouryears.eu/wp-content/uploads/pydsl/

您可能需要采取各种技巧来使其实用。例如,在上面链接提供的代码中,您不能使用内置函数和语言结构,例如 @my_dsl 函数中的 for 循环和 if 语句。不过,您可以通过向 Env 类添加更多行为来实现这些功能。

更新. 这里 是对同一事物的稍微详细的解释。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top