4

假设我需要创建自己的小型 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 表达式的这种“引用”功能?

4

3 回答 3

3

我不确定这是个好主意,但我想我会试一试。总结一下:

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
于 2010-04-17T01:37:56.890 回答
2

您可能想查看Python 中包含的用于解析、访问和转换输入代码的抽象语法树(或解析树)的模块astparser据我所知,用 Python 编写的Sage 数学系统具有类似的预编译器。

于 2010-04-17T00:12:08.437 回答
-1

针对 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 类添加更多行为来使这些工作。

更新是对同一件事的稍微详细的解释。

于 2010-05-18T12:36:02.437 回答