代码之家  ›  专栏  ›  技术社区  ›  laike9m

在Python3.7中,sys.settrace中的“opcode”事件是否提供了有关字节码本身的任何信息?

  •  1
  • laike9m  · 技术社区  · 6 年前

    所以我在玩 sys.settrace 功能。在python 3.7中, opcode 事件已添加

    'opcode'
    解释器将要执行一个新的操作码(有关 操作码详细信息)。调用本地跟踪函数;arg为none;调用 返回值指定新的本地跟踪函数。每个操作码事件 默认情况下不会发出:它们必须由 设置 f_trace_opcodes 在帧上为真。

    我能够得到这些操作码事件,但是似乎没有更多的信息,我甚至不知道操作码是什么,它在做什么。

    此事件是否只带来更精细的粒度,而不提供任何额外信息?

    1 回复  |  直到 5 年前
        1
  •  0
  •   Noctis Skytower    5 年前

    如果您需要进一步的信息,您需要检查 frame 传递到跟踪函数的参数。尤其是,你想看看 frame.f_lasti 查找最后执行的指令和 frame.f_code.co_code 访问该指令。同时使用这两个代码将给出实际的操作码。如果你想用助记符,那你就要用 dis.opname ;但是,如果您只是简单地将它与另一个操作码进行匹配,那么您可以使用 dis.opmap 相反。下面的示例是人为的,但它演示了使用刚刚提供的提示可能实现的一些功能:

    #! /usr/bin/env python3
    import dis
    import sys
    
    
    def main():
        dis.dis(add)
        sys.settrace(get_trace(False, get_callback(celebrate)))
        total = add(1, 2)
        print(f'total = {total}')
        sys.settrace(None)
        total = add(3, 4)
        print(f'total = {total}')
        print('Done')
    
    
    def get_trace(trace_lines=True, opcode_callback=None):
        trace_opcodes = callable(opcode_callback)
    
        # noinspection PyUnusedLocal
        def trace(frame, event, arg):
            frame.f_trace_lines = trace_lines
            frame.f_trace_opcodes = trace_opcodes
            if trace_opcodes and event == 'opcode':
                opcode = frame.f_code.co_code[frame.f_lasti]
                opname = dis.opname[opcode]
                opcode_callback(frame, opcode, opname)
            return trace
    
        return trace
    
    
    def get_callback(return_handler=None):
        handle_return = callable(return_handler)
    
        def echo_opcode(frame, opcode, opname):
            print(f'# {opname} ({opcode}) #')
            if handle_return and opcode == dis.opmap['RETURN_VALUE']:
                return_handler(frame)
    
        return echo_opcode
    
    
    # noinspection PyUnusedLocal
    def celebrate(frame):
        print('/-------------------\\')
        print('| We are returning! |')
        print('\\-------------------/')
    
    
    def add(a, b):
        return a + b
    
    
    if __name__ == '__main__':
        main()