Skip to content

dis

The Python dis module is CPython’s bytecode disassembler. It translates compiled bytecode into human-readable instructions, enabling developers to inspect how Python source code is executed by the interpreter.

Here’s a quick look at disassembling a simple function:

Python
>>> import dis
>>> def greet(name):
...     msg = "Hello, " + name
...     return msg
...
>>> dis.dis(greet)
  1           RESUME                   0

  2           LOAD_CONST               0 ('Hello, ')
              LOAD_FAST_BORROW         0 (name)
              BINARY_OP                0 (+)
              STORE_FAST               1 (msg)

  3           LOAD_FAST_BORROW         1 (msg)
              RETURN_VALUE

Each row shows a source line number, an instruction name (opcode), and any argument with its resolved value in parentheses. Exact instruction names vary across CPython versions.

Key Features

  • Disassembles functions, methods, classes, modules, code objects, and source strings
  • Provides programmatic access to instructions via get_instructions() and the Bytecode class
  • Returns source line numbers, jump targets, and argument details for each instruction
  • Exposes code object metadata, such as variable names, constants, and argument counts
  • Includes a command-line interface, python -m dis
  • Supports adaptive (specialized) bytecode inspection

Frequently Used Classes and Functions

Object Type Description
dis.dis() Function Disassembles a function, class, module, or source string and prints the result
dis.get_instructions() Function Returns an iterator of Instruction objects for each bytecode operation
dis.code_info() Function Returns a formatted string with code object metadata such as variable names and constants
dis.show_code() Function Prints code object metadata to stdout
dis.findlinestarts() Function Yields (offset, lineno) pairs for each source line start in a code object
dis.findlabels() Function Returns a list of bytecode offsets that are jump targets
dis.Bytecode Class Iterable wrapper around a code object that yields Instruction instances
dis.Instruction Class Named tuple holding the opcode, argument, source line, and position for one instruction
dis.Positions Class Holds fine-grained source location info (line, column) attached to each instruction

Examples

Using get_instructions() to iterate over instructions programmatically:

Python
>>> import dis
>>> def double(x):
...     return x * 2
...
>>> [instr.opname for instr in dis.get_instructions(double)]
[
    'RESUME',
    'LOAD_FAST_BORROW',
    'LOAD_SMALL_INT',
    'BINARY_OP',
    'RETURN_VALUE'
]

Using the Bytecode class to capture disassembly as a string and inspect code metadata:

Python
>>> import dis
>>> def double(x):
...     return x * 2
...
>>> bc = dis.Bytecode(double)
>>> print(bc.dis())
  1           RESUME                   0

  2           LOAD_FAST_BORROW         0 (x)
              LOAD_SMALL_INT           2
              BINARY_OP                5 (*)
              RETURN_VALUE

>>> print(bc.info())
Name:              double
Filename:          <stdin>
Argument count:    1
...

Inspecting code object details with the code_info() function:

Python
>>> import dis
>>> def greet(name):
...     return "Hello, " + name
...
>>> print(dis.code_info(greet))
Name:              greet
Filename:          <stdin>
Argument count:    1
Positional-only arguments: 0
Kw-only arguments: 0
Number of locals:  1
Stack size:        2
Flags:             OPTIMIZED, NEWLOCALS
Constants:
   0: 'Hello, '
Variable names:
   0: name

Common Use Cases

The most common tasks for dis include:

  • Comparing two implementations of the same logic to understand which generates fewer instructions
  • Tracing the source of unexpected behavior by examining the exact instructions a code path executes
  • Understanding how Python features, such as comprehensions, closures, and generators compile to bytecode
  • Building static analysis tools that inspect function bytecode programmatically
  • Exploring CPython internals and learning how the Python virtual machine works

Real-World Example

The following script uses dis to compare two string-joining implementations and count their instructions:

Python compare_str_join.py
import dis

def join_manual(words):
    result = ""
    for word in words:
        result = result + word + ", "
    return result.rstrip(", ")

def join_builtin(words):
    return ", ".join(words)

for func in (join_manual, join_builtin):
    count = sum(1 for _ in dis.get_instructions(func))
    print(f"{func.__name__}: {count} instructions")

print()
print("join_builtin disassembly:")
dis.dis(join_builtin)

Run it:

Shell
$ python compare_str_join.py
join_manual: 20 instructions
join_builtin: 6 instructions

join_builtin disassembly:
  1           RESUME                   0

  2           LOAD_CONST               0 (', ')
              LOAD_ATTR                1 (join + NULL|self)
              LOAD_FAST_BORROW         0 (words)
              CALL                     1
              RETURN_VALUE

The instruction count confirms that join_builtin() compiles to significantly fewer bytecode operations, reflecting the efficiency advantage of the built-in str.join() method over manual concatenation in a loop.

Tutorial

Your Guide to the CPython Source Code

In this detailed Python tutorial, you'll explore the CPython source code. By following this step-by-step walkthrough, you'll take a deep dive into how the CPython compiler works and how your Python code gets executed.

advanced python

For additional information on related topics, take a look at the following resources:


By Leodanis Pozo Ramos • Updated April 2, 2026