我想尝试使用Python解释器并创建一个小型DSL。是否有任何模块可以让我做类似于这个理论代码(类似于LINQ表达式树)的事情?
expression_tree = Function(
Print(
String('Hello world!')
)
)
compile_to_bytecode(expression_tree)
或者只是生成Python源代码会更容易吗?使用C、SWIG或Cython能否使这个过程更简单?
我想尝试使用Python解释器并创建一个小型DSL。是否有任何模块可以让我做类似于这个理论代码(类似于LINQ表达式树)的事情?
expression_tree = Function(
Print(
String('Hello world!')
)
)
compile_to_bytecode(expression_tree)
或者只是生成Python源代码会更容易吗?使用C、SWIG或Cython能否使这个过程更简单?
通过使用ast
并将树编译成字节码,正如另一个答案所建议的那样,可能是最简单的方法;生成源代码并进行编译,几乎同样好。
但是,如果想要探索更低级别的方法,请查看此页面中的链接;我发现byteplay特别有用(目前无法在2.6或3.*上工作,仅适用于2.4或2.5,但我认为在其跟踪器中当前正在讨论很容易修复为2.6)。我没有使用Phil Eby的类似功能的BytecodeAssembler,但考虑到作者的声誉,我相信值得一试!
compiler
模块及其ast
子模块来处理此问题(但请注意,自2.6版本以后,此模块已被弃用)。在Python 3.X中,您只需要使用ast
。
两者都提供了一个compile()
函数,可以将源代码/AST转换为“可由exec
语句或eval()
执行的代码对象”。生成Python代码并运行它更容易。如果这样做,您还可以更轻松地调试它,因为调试器有实际的源代码来显示。另请参见Python杂志7月号中Malte Borch的文章,其中他谈到了这个问题以及其他内容。
更新至Python3 - 还有一个非常有趣的汇编程序zachariahreed/byteasm
。
实际上,这是我在Py3中唯一能用的。它具有非常好的、清晰的API:
>>> import byteasm, dis
>>> b = byteasm.FunctionBuilder()
>>> b.add_positional_arg('x')
>>> b.emit_load_const('Hello!')
>>> b.emit_load_fast('x')
>>> b.emit_build_tuple(2)
>>> b.emit_return_value()
>>> f = b.make('f')
>>> f
<function f at 0xb7012a4c>
>>> dis.dis(f)
1 0 LOAD_CONST 0 ('Hello!')
3 LOAD_FAST 0 (x)
6 BUILD_TUPLE 2
9 RETURN_VALUE
>>> f(108)
('Hello!', 108)
Fernando Meyer 最近写了一篇博客文章,解释了如何使用 # coding
指令来指定自己的 Python 扩展。示例(实际格式定义在 pyspec.py 和 tokenizer.py 中):
# coding: pyspec
class Bow:
def shot(self):
print "got shot"
def score(self):
return 5
describe Bowling:
it "should score 0 for gutter game":
bowling = Bow()
bowling.shot()
assert that bowling.score.should_be(5)
请查看此处找到的反汇编模块: