9.25 拆解Python字节码
模块可以被用来输出任何Python函数的反编译结果。例如:
当你想要知道你的程序底层的运行机制的时候,dis
模块是很有用的。比如如果你想试着理解性能特征。被 函数解析的原始字节码如下所示:
- >>> countdown.__code__.co_code
- b"x'\x00|\x00\x00d\x01\x00k\x04\x00r)\x00t\x00\x00d\x02\x00|\x00\x00\x83
- \x02\x00\x01|\x00\x00d\x03\x008}\x00\x00q\x03\x00Wt\x00\x00d\x04\x00\x83
- \x01\x00\x01d\x00\x00S"
- >>>
奇怪的是,在 模块中并没有函数让你以编程方式很容易的来处理字节码。不过,下面的生成器函数可以将原始字节码序列转换成 opcodes
和参数。
- import opcode
- def generate_opcodes(codebytes):
- extended_arg = 0
- i = 0
- n = len(codebytes)
- while i < n:
- i += 1
- if op >= opcode.HAVE_ARGUMENT:
- oparg = codebytes[i] + codebytes[i+1]*256 + extended_arg
- extended_arg = 0
- i += 2
- if op == opcode.EXTENDED_ARG:
- extended_arg = oparg * 65536
- continue
- else:
- oparg = None
- yield (op, oparg)
使用方法如下:
- >>> def add(x, y):
- ... return x + y
- ...
- >>> c = add.__code__
- <code object add at 0x1007beed0, file "<stdin>", line 1>
- >>> c.co_code
- b'|\x00\x00|\x01\x00\x17S'
- >>>
- >>> # Make a completely new code object with bogus byte code
- >>> import types
- >>> newbytecode = b'xxxxxxx'
- >>> nc = types.CodeType(c.co_argcount, c.co_kwonlyargcount,
- ... c.co_nlocals, c.co_stacksize, c.co_flags, newbytecode, c.co_consts,
- ... c.co_names, c.co_varnames, c.co_filename, c.co_name,
- ... c.co_firstlineno, c.co_lnotab)
- >>> nc
- <code object add at 0x10069fe40, file "<stdin>", line 1>
- >>> add.__code__ = nc
- >>> add(2,3)
你可以像这样耍大招让解释器奔溃。但是,对于编写更高级优化和元编程工具的程序员来讲,他们可能真的需要重写字节码。本节最后的部分演示了这个是怎样做到的。你还可以参考另外一个类似的例子:
原文: