Reputation: 19358
So I'm playing with the sys.settrace
function. In Python 3.7, a new opcode
event is added
'opcode'
The interpreter is about to execute a new opcode (see dis for opcode details). The local trace function is called; arg is None; the return value specifies the new local trace function. Per-opcode events are not emitted by default: they must be explicitly requested by settingf_trace_opcodes
to True on the frame.
I was able to get those opcode events, however there seems to be no further information——I don't even know what the opcode is and what it's doing.
Does this event only brings finer granularity, without giving any extra information?
Upvotes: 2
Views: 830
Reputation: 22011
If you want further information, you will need to examine the frame
argument that is passed into the tracing function. In particular, you want to look at frame.f_lasti
to find the last instruction executed and frame.f_code.co_code
to access that instruction. Using those two together will give you the actual opcode. If you want the mnemonic, then you will want to use dis.opname
; but if you simply what to match it with another opcode, then you can use dis.opmap
instead. The following example is contrived, but it demonstrates some of what is possible using the hints just provided:
#! /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()
Upvotes: 2