New submission from S Murthy <smur...@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 <rep...@bugs.python.org>
<https://bugs.python.org/issue39800>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to