有没有办法以编程方式生成Python字节码?

时间:2009-09-26 20:01:18

标签: python expression-trees abstract-syntax-tree dsl bytecode

我想破解Python解释器并尝试创建一个小型DSL。是否有任何模块我可以做这样的理论代码(类似于LINQ表达式树)?

expression_tree = Function(
    Print(
        String('Hello world!')
    )
 )
compile_to_bytecode(expression_tree)

或者只是更容易生成Python源代码?使用C或SWIG或Cython可以使这更容易吗?

6 个答案:

答案 0 :(得分:11)

通过ast工作并将树编译成字节码,正如另一个答案所暗示的那样,可能是最简单的;生成源并编译它们几乎一样好。

但是,要探索更低级别的方法,请查看this page的链接;我发现byteplay特别有用(目前不适用于2.6或3. *,只有2.4或2.5,但我认为修复2.6应该很容易,正如其目前在其跟踪器中所讨论的那样)。我没有使用Phil Eby的同样功能BytecodeAssembler,但考虑到作者的声誉,我确信值得一试!

答案 1 :(得分:5)

在Python 2.X中,您通常会使用compiler module及其ast子模块来处理此问题(但请注意,自2.6版本以来,此模块已弃用)。在Python 3.X中,您只需使用ast

两者都提供compile()函数,它将从源/ AST转到“可以由exec语句或eval()执行的代码对象。”

答案 2 :(得分:2)

生成Python代码并运行它更容易。如果你这样做,你也可以更容易地调试它,因为有调试器的实际来源可以显示。另见Python杂志7月刊中的Malte Borchs文章,其中还讨论了这一点。

答案 3 :(得分:1)

Fernando Meyer recently wrote a blog post解释如何使用# coding指令指定自己的Python扩展。示例(实际格式定义位于pyspec.pytokenizer.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)

答案 4 :(得分:1)

更新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)

答案 5 :(得分:0)

查看此处的反汇编程序模块:

http://docs.python.org/library/dis.html