This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author smurthy
Recipients smurthy
Date 2020-02-29.15:27:53
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1582990073.8.0.514436528319.issue39800@roundup.psfhosted.org>
In-reply-to
Content
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)
History
Date User Action Args
2020-02-29 15:27:53smurthysetrecipients: + smurthy
2020-02-29 15:27:53smurthysetmessageid: <1582990073.8.0.514436528319.issue39800@roundup.psfhosted.org>
2020-02-29 15:27:53smurthylinkissue39800 messages
2020-02-29 15:27:53smurthycreate