重新编译 Python 字节码指令
Recompile Python bytecode instructions
假设我有一个 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
, I can get a sequence of dis.Instruction
s:
>>> 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
可变代码对象:
>>> code_object = compile_back(dis.get_instructions(speak))
>>> exec(code_object)
moo
dis.Bytecode
中的 Instruction
个对象序列不足以重建代码对象。代码对象不仅仅是一系列指令;它包括大量其他数据,如参数计数、计算堆栈的大小、指示各种属性的标志等。大多数这些东西都(简要地)在 table in the inspect
module docs, but there's even some "scratch space" 中描述,无法通过普通方式访问。
Instruction
个对象足以恢复大量代码对象的信息,但不是全部。通过一些危险的假设,您可能能够得到通常有效的东西,但最好首先从原始代码对象中保留更多信息。
无论如何,没有直截了当的方法。
假设我有一个 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
, I can get a sequence of dis.Instruction
s:
>>> 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
可变代码对象:
>>> code_object = compile_back(dis.get_instructions(speak))
>>> exec(code_object)
moo
dis.Bytecode
中的 Instruction
个对象序列不足以重建代码对象。代码对象不仅仅是一系列指令;它包括大量其他数据,如参数计数、计算堆栈的大小、指示各种属性的标志等。大多数这些东西都(简要地)在 table in the inspect
module docs, but there's even some "scratch space" 中描述,无法通过普通方式访问。
Instruction
个对象足以恢复大量代码对象的信息,但不是全部。通过一些危险的假设,您可能能够得到通常有效的东西,但最好首先从原始代码对象中保留更多信息。
无论如何,没有直截了当的方法。