9.25 拆解Python字节码

    模块可以被用来输出任何Python函数的反编译结果。例如:

    当你想要知道你的程序底层的运行机制的时候,dis 模块是很有用的。比如如果你想试着理解性能特征。被 函数解析的原始字节码如下所示:

    1. >>> countdown.__code__.co_code
    2. b"x'\x00|\x00\x00d\x01\x00k\x04\x00r)\x00t\x00\x00d\x02\x00|\x00\x00\x83
    3. \x02\x00\x01|\x00\x00d\x03\x008}\x00\x00q\x03\x00Wt\x00\x00d\x04\x00\x83
    4. \x01\x00\x01d\x00\x00S"
    5. >>>

    奇怪的是,在 模块中并没有函数让你以编程方式很容易的来处理字节码。不过,下面的生成器函数可以将原始字节码序列转换成 opcodes 和参数。

    1. import opcode
    2.  
    3. def generate_opcodes(codebytes):
    4. extended_arg = 0
    5. i = 0
    6. n = len(codebytes)
    7. while i < n:
    8. i += 1
    9. if op >= opcode.HAVE_ARGUMENT:
    10. oparg = codebytes[i] + codebytes[i+1]*256 + extended_arg
    11. extended_arg = 0
    12. i += 2
    13. if op == opcode.EXTENDED_ARG:
    14. extended_arg = oparg * 65536
    15. continue
    16. else:
    17. oparg = None
    18. yield (op, oparg)

    使用方法如下:

    1. >>> def add(x, y):
    2. ... return x + y
    3. ...
    4. >>> c = add.__code__
    5. <code object add at 0x1007beed0, file "<stdin>", line 1>
    6. >>> c.co_code
    7. b'|\x00\x00|\x01\x00\x17S'
    8. >>>
    9. >>> # Make a completely new code object with bogus byte code
    10. >>> import types
    11. >>> newbytecode = b'xxxxxxx'
    12. >>> nc = types.CodeType(c.co_argcount, c.co_kwonlyargcount,
    13. ... c.co_nlocals, c.co_stacksize, c.co_flags, newbytecode, c.co_consts,
    14. ... c.co_names, c.co_varnames, c.co_filename, c.co_name,
    15. ... c.co_firstlineno, c.co_lnotab)
    16. >>> nc
    17. <code object add at 0x10069fe40, file "<stdin>", line 1>
    18. >>> add.__code__ = nc
    19. >>> add(2,3)

    你可以像这样耍大招让解释器奔溃。但是,对于编写更高级优化和元编程工具的程序员来讲,他们可能真的需要重写字节码。本节最后的部分演示了这个是怎样做到的。你还可以参考另外一个类似的例子:

    原文: