Skip to content

pickletools

The Python pickletools module contains helpers for analyzing and optimizing data produced by the pickle module. It can disassemble a pickle stream into a human-readable listing of opcodes, iterate over the individual operations, or strip unused memo entries to produce a smaller stream. Because it inspects the bytes of a pickle without actually reconstructing the stored objects, it is also a safer way to look inside an untrusted pickle than pickle.load() itself.

Here’s a quick example:

Language: Python
>>> import pickle, pickletools

>>> blob = pickle.dumps((1, 2))
>>> pickletools.dis(blob)
    0: \x80 PROTO      5
    2: \x95 FRAME      7
   11: K    BININT1    1
   13: K    BININT1    2
   15: \x86 TUPLE2
   16: \x94 MEMOIZE    (as 0)
   17: .    STOP
highest protocol among opcodes = 4

Each line corresponds to one pickle opcode, along with its position in the stream and its decoded argument.

Key Features

  • Disassembles a pickle stream into a readable opcode listing with dis()
  • Iterates over individual opcodes, arguments, and positions through genops()
  • Rewrites a pickle with optimize() to remove unused PUT and MEMOIZE operations
  • Supports a command-line entry point invoked with python -m pickletools
  • Reads pickle data from either a bytes object or any binary file-like object
  • Operates without importing or instantiating the objects stored in the pickle, which avoids executing arbitrary code

Frequently Used Classes and Functions

Object Type Description
pickletools.dis() Function Writes a symbolic disassembly of a pickle to an output stream
pickletools.genops() Function Yields (opcode, arg, position) tuples for every operation in a pickle
pickletools.optimize() Function Returns an equivalent pickle with unused memo slots removed

Examples

Disassembling a pickle that contains a small dictionary:

Language: Python
>>> import pickle, pickletools

>>> blob = pickle.dumps({"name": "Ada", "tags": [1, 2, 3]})
>>> pickletools.dis(blob)
    0: \x80 PROTO      5
    2: \x95 FRAME      35
   11: }    EMPTY_DICT
   12: \x94 MEMOIZE    (as 0)
   13: (    MARK
   14: \x8c     SHORT_BINUNICODE 'name'
   20: \x94     MEMOIZE    (as 1)
   21: \x8c     SHORT_BINUNICODE 'Ada'
   26: \x94     MEMOIZE    (as 2)
   27: \x8c     SHORT_BINUNICODE 'tags'
   33: \x94     MEMOIZE    (as 3)
   34: ]        EMPTY_LIST
   35: \x94     MEMOIZE    (as 4)
   36: (        MARK
   37: K            BININT1    1
   39: K            BININT1    2
   41: K            BININT1    3
   43: e            APPENDS    (MARK at 36)
   44: u        SETITEMS   (MARK at 13)
   45: .    STOP
highest protocol among opcodes = 4

Adding short descriptions to each opcode with annotate=1:

Language: Python
>>> import pickle, pickletools

>>> blob = pickle.dumps(1)
>>> pickletools.dis(blob, annotate=1)
    0: \x80 PROTO      5 Protocol version indicator.
    2: K    BININT1    1 Push a one-byte unsigned integer.
    4: .    STOP         Stop the unpickling machine.
highest protocol among opcodes = 2

Iterating over the opcodes programmatically with the genops() function:

Language: Python
>>> import pickle, pickletools

>>> blob = pickle.dumps([10, 20])
>>> for opcode, arg, pos in pickletools.genops(blob):
...     print(pos, opcode.name, arg)
...
0 PROTO 5
2 FRAME 9
11 EMPTY_LIST None
12 MEMOIZE None
13 MARK None
14 BININT1 10
16 BININT1 20
18 APPENDS None
19 STOP None

Shrinking a pickle by removing unused memo slots:

Language: Python
>>> import pickle, pickletools

>>> blob = pickle.dumps({"name": "Ada", "tags": [1, 2, 3]})
>>> optimized = pickletools.optimize(blob)
>>> len(blob), len(optimized)
(46, 41)

>>> pickle.loads(optimized) == pickle.loads(blob)
True

Running the module from the command line on a saved pickle file:

Language: Shell
$ python -m pickletools data.pickle
    0: \x80 PROTO      5
    2: \x95 FRAME      7
   11: K    BININT1    1
   13: K    BININT1    2
   15: \x86 TUPLE2
   16: \x94 MEMOIZE    (as 0)
   17: .    STOP
highest protocol among opcodes = 4

Common Use Cases

The most common tasks for pickletools include:

  • Debugging unexpected output or errors from pickle.dump() and pickle.load()
  • Inspecting untrusted pickle files without importing or executing their contents
  • Teaching or learning how the pickle protocol encodes Python objects
  • Shrinking persisted pickles or network payloads with optimize()
  • Comparing different pickle protocols to see how they encode the same value

Real-World Example

Consider a helper that groups every opcode in a pickle by name and reports the most frequent operations, which is a handy first step when profiling a large persisted data set:

Language: Python
>>> import pickle, pickletools
>>> from collections import Counter

>>> users = [{"id": i} for i in range(4)]
>>> blob = pickle.dumps(users)
>>> counts = Counter(op.name for op, _, _ in pickletools.genops(blob))
>>> counts.most_common(4)
[('MEMOIZE', 6), ('EMPTY_DICT', 4), ('BININT1', 4), ('SETITEM', 4)]

The helper uses genops() to walk through the stream exactly once, extracts the opcode name for each step, and feeds the names into a Counter to rank them. No object in the pickle is ever reconstructed, which makes this kind of analysis safe to run on pickles that came from an untrusted source.

Tutorial

The Python pickle Module: How to Persist Objects in Python

In this tutorial, you'll learn how you can use the Python pickle module to convert your objects into a stream of bytes that can be saved to a disk or sent over a network. You'll also learn the security implications of using this process on objects from an untrusted source.

intermediate python

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


By Leodanis Pozo Ramos • Updated May 7, 2026