重新编译Python字节码指令

时间:2018-04-03 14:14:49

标签: python python-3.x bytecode bytecode-manipulation

假设我有一个speak函数:

def speak():
    print("moo")

我可以通常使用dis.dis来反汇编它:

>>> dis.dis(speak)
  2           0 LOAD_GLOBAL              0 (print)
              3 LOAD_CONST               1 ('moo')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE

但我想将与speak函数关联的代码对象破坏为一系列指令,然后将它们编译回来。 在dis.Bytecode的帮助下,我可以获得代表代码对象的dis.Instruction序列:

>>> bytecode = dis.Bytecode(speak)
>>> for instruction in bytecode:
...     print(instruction)
... 
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=2, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval='moo', argrepr="'moo'", offset=3, starts_line=None, is_jump_target=False)
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=6, starts_line=None, is_jump_target=False)
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=9, starts_line=None, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=10, starts_line=None, is_jump_target=False)
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=13, starts_line=None, is_jump_target=False)

有没有一种直接的方法可以将这些Instruction对象编译到原始代码对象中?

例如,我正在寻找一个compile_back函数,该函数将接受一系列指令并输出exec utable代码对象:

>>> code_object = compile_back(dis.get_instructions(speak))
>>> exec(code_object)
moo

1 个答案:

答案 0 :(得分:2)

来自Instruction的{​​{1}}个对象序列不足以重建代码对象。代码对象不仅仅是一系列指令;它包含大量其他数据,例如参数计数,评估堆栈的大小,指示各种属性的标志等。大多数这些事情(简要地)在dis.Bytecode模块的table中描述docs,但甚至有些"scratch space"无法通过普通手段访问。

inspect个对象足以恢复很多代码对象的信息,但不是全部。有了一些危险的假设,你可能会得到一些通常有效的东西,但最好是从原始代码对象中获取更多信息。

无论如何,没有直截了当的方式。