假设我需要创建自己的小型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表达式的这种“引用”功能吗?
答案 0 :(得分:3)
我不确定这是个好主意,但我想我give it a try。总结一下:
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
答案 1 :(得分:2)
您可能希望查看Python中包含的ast
或parser
模块,以解析,访问和转换输入代码的抽象语法树(或分别为解析树)。据我所知,用Python编写的Sage mathematical system有一个类似的预编译器。
答案 2 :(得分:-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完成大部分解析工作。
这个想法是基于Ian提到的简单exec <code> in <environment>
声明,其中包含一个强加的内容。也就是说,必须稍微调整函数的字节码,并将所有局部变量访问操作(LOAD_FAST)切换到环境(LOAD_NAME)的变量访问。
显示比说明更简单:http://fouryears.eu/wp-content/uploads/pydsl/
你可能想要做些各种技巧来实现它。例如,在上面链接中提供的代码中,您不能使用内置函数和语言结构,例如@my_dsl函数中的for循环和if语句。但是,您可以通过向Env类添加更多行为来实现这些功能。
更新的。 Here对同一事情的解释稍微冗长。