[New-bugs-announce] [issue39800] Inconsistent/incomplete disassembly of methods vs method source code

S Murthy report at bugs.python.org
Sat Feb 29 10:27:53 EST 2020


New submission from S Murthy <smurthy at pm.me>:

I am using the dis module to look at source (and logical) lines of code vs corresponding bytecode instructions. I am bit confused by the output of dis.dis when disassembling a given method vs the corresponding source string, e.g.

>>> def f(x): return x**2
>>> dis.dis(f)
  1 0 LOAD_FAST              0 (x)
  2 LOAD_CONST               1 (2)
  4 BINARY_POWER
  6 RETURN_VALUE

This is the bytecode instruction block for the body only (not the method header), but dis.dis('def f(x): return x**2') produces the instructions for the header and body:

>>> dis.dis('def f(x): return x**2')
  1 0 LOAD_CONST               0 (<code object f at 0x10b0f7f60, file "<dis>", line 1>)
  2 LOAD_CONST               1 ('f')
  4 MAKE_FUNCTION            0
  6 STORE_NAME               0 (f)
  8 LOAD_CONST               2 (None)
 10 RETURN_VALUE

Disassembly of <code object f at 0x10b0f7f60, file "<dis>", line 1>:
  1 0 LOAD_FAST              0 (x)
  2 LOAD_CONST               1 (2)
  4 BINARY_POWER
  6 RETURN_VALUE

I have traced this difference to the different behaviour of dis.dis for methods vs source code strings:

def dis(x=None, *, file=None, depth=None):
    ...
    ...
    if hasattr(x, '__code__'):
        x = x.__code__
    ...
    # Perform the disassembly
    ...
    elif hasattr(x, 'co_code'): # Code object
        _disassemble_recursive(x, file=file, depth=depth)
    ...
    elif isinstance(x, str):    # Source code
        _disassemble_str(x, file=file, depth=depth)    
    ...

It appears as if the method body is contained in the code object produced from compiling the source (_try_compile(source, '<dis>', ...)) but not if the code object was obtained from f.__code__.

Why is this the case, and would it not be better to for dis.dis to behave consistently for methods and source strings of methods, and to generate/produce the complete instruction set, including for any headers? The current behaviour of dis.dis means that Bytecode(x) is also affected, as iterating over the instructions gives you different instructions depending on whether x is a method or a source string of x:

>>> for instr in dis.Bytecode(f): 
...     print(instr) 
...
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='x', argrepr='x', offset=0, starts_line=1, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=2, argrepr='2', offset=2, starts_line=None, is_jump_target=False)
Instruction(opname='BINARY_POWER', opcode=19, arg=None, argval=None, argrepr='', offset=4, starts_line=None, is_jump_target=False)
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=6, starts_line=None, is_jump_target=False

>>> for instr in dis.Bytecode(inspect.getsource(f)): 
...     print(instr) 
...
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=<code object f at 0x11e4036f0, file "<disassembly>", line 1>, argrepr='<code object f at 0x11e4036f0, file "<disassembly>", line 1>', offset=0, starts_line=1, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval='f', argrepr="'f'", offset=2, starts_line=None, is_jump_target=False)
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=0, argval=0, argrepr='', offset=4, starts_line=None, is_jump_target=False)
Instruction(opname='STORE_NAME', opcode=90, arg=0, argval='f', argrepr='f', offset=6, starts_line=None, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=None, argrepr='None', offset=8, starts_line=None, is_jump_target=False)
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=10, starts_line=None, is_jump_target=False)

----------
components: Library (Lib)
messages: 362985
nosy: smurthy
priority: normal
severity: normal
status: open
title: Inconsistent/incomplete disassembly of methods vs method source code
type: behavior
versions: Python 3.7

_______________________________________
Python tracker <report at bugs.python.org>
<https://bugs.python.org/issue39800>
_______________________________________


More information about the New-bugs-announce mailing list