The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Serialize to bytes | payload = pickle.dumps(value, protocol=pickle.HIGHEST_PROTOCOL) | View examples |
| Load trusted bytes | value = pickle.loads(payload) | View examples |
| Write a pickle file | with open(path, 'wb') as stream: pickle.dump(value, stream, protocol=5) | View examples |
| Read the newest protocol | protocol = pickle.HIGHEST_PROTOCOL | View examples |
| Target protocol 4 | payload = pickle.dumps(value, protocol=4) | View examples |
| Read the default protocol | protocol = pickle.DEFAULT_PROTOCOL | View examples |
| Customize serialized state | def __getstate__(self):
return {'version': 1, 'value': self.value} | View examples |
| Restore validated state | def __setstate__(self, state):
self.value = validate(state) | View examples |
| Define a reduction | def __reduce__(self): return (type(self), (self.value,)) | View examples |
| Register a type reducer | copyreg.pickle(ValueType, reduce_value) | View examples |
| Use a private reducer table | pickler.dispatch_table = {ValueType: reduce_value} | View examples |
| Emit an external identifier | def persistent_id(self, obj): return ('Record', obj.key) | View examples |
| Resolve an external identifier | def persistent_load(self, pid):
return repository.fetch(pid) | View examples |
| Open a shelf | with shelve.open(path, flag='c', writeback=False) as db: use(db) | View examples |
| Persist a mutable update | value = db[key]; value.append(item); db[key] = value | View examples |
| Synchronize a shelf | db.sync() | View examples |
| Disassemble without loading | python -m pickletools payload.pickle | View examples |
| Override global resolution | def find_class(self, module, name):
raise pickle.UnpicklingError('globals forbidden') | View examples |
pickle preserves Python object graphs, including shared references and custom class state; that power also lets malicious payloads invoke code during loading. It is therefore an internal trusted-data format, not a safe interchange format. shelve adds string-keyed persistence over pickle and a DBM backend, but does not add trust, concurrency, or cross-platform guarantees.
Step by step
Detailed examples
Round-trip trusted object graphs
dumps and dump serialize an object graph; loads and load reconstruct it by importing referenced definitions. Shared references and recursive structures are preserved within a pickle operation. The format is Python-specific and class code must remain importable, so schema-oriented JSON, CSV, or a database is usually better for long-lived cross-language data.
import pickle
shared = [1, 2]
value = {"left": shared, "right": shared}
restored = pickle.loads(pickle.dumps(value, protocol=4))
print(restored)
print(restored["left"] is restored["right"]) {'left': [1, 2], 'right': [1, 2]}
TrueChoose protocols for the oldest reader
Higher protocols can be smaller or faster but require a sufficiently new Python. Protocol 5 supports out-of-band buffers and became the default protocol in Python 3.14; HIGHEST_PROTOCOL is appropriate only when every reader is controlled. Persist the producer version and schema separately, and test migrations before upgrading writers.
import pickle
print(pickle.HIGHEST_PROTOCOL >= pickle.DEFAULT_PROTOCOL)
payload = pickle.dumps({"ok": True}, protocol=4)
print(pickle.loads(payload)) True
{'ok': True}Evolve class state explicitly
Implement __getstate__ to remove transient values and __setstate__ to validate or migrate restored state. Keep definitions at module scope with stable qualified names. Renaming modules or classes breaks ordinary loading unless compatibility shims or a custom Unpickler map old names; constructors are not necessarily called during unpickling, so validation belongs in restoration logic too.
import pickle
class Record:
def __init__(self, value: int):
self.value = value
self.cache = value * 10
def __getstate__(self):
return {"value": self.value}
def __setstate__(self, state):
self.value = state["value"]
self.cache = self.value * 10
record = pickle.loads(pickle.dumps(Record(7), protocol=4))
print(record.value, record.cache) 7 70Register stable reductions for controlled types
A reduction specifies the callable and arguments used to rebuild an object. Prefer a simple importable reconstruction function and primitive state. copyreg registers reductions globally for a type, while a Pickler dispatch_table can isolate policy to one writer. Never accept a reducer supplied by untrusted data; loading chooses and invokes globals encoded in the pickle.
import pickle
class Point:
def __init__(self, x: int, y: int):
self.x, self.y = x, y
def __reduce__(self):
return (Point, (self.x, self.y))
point = pickle.loads(pickle.dumps(Point(3, 4), protocol=4))
print(point.x, point.y) 3 4Keep external objects outside the pickle
Pickler.persistent_id can replace selected objects with application identifiers, and Unpickler.persistent_load resolves them from a trusted store. Include a type tag and validate every identifier to prevent confused-deputy lookups. This separates object-graph structure from large or shared records, but the pickle stream itself remains executable and trusted-only.
def resolve(pid: tuple[str, int], records: dict[int, str]) -> str:
kind, key = pid
if kind != "Record":
raise ValueError("unsupported persistent object")
return records[key]
print(resolve(("Record", 7), {7: "saved"})) savedTreat shelve as a single-writer trusted store
Shelf keys are strings and values are pickled. The backing DBM implementation and files vary by platform, and concurrent read/write access is not supported unless the underlying implementation explicitly provides it. With writeback=False, mutate a value by assigning it back; writeback=True caches every accessed value and can consume memory or make close unexpectedly slow.
import shelve
import tempfile
with tempfile.TemporaryDirectory() as directory:
path = directory + "/state"
with shelve.open(path) as db:
db["items"] = [2, 3]
with shelve.open(path, flag="r") as db:
print(db["items"])
print(sorted(db.keys())) [2, 3]
['items']Never load an untrusted pickle
Unpickling can execute arbitrary code before a returned value can be inspected. Authentication can detect tampering only when secret-key handling and verification occur before loading; it does not make an untrusted producer safe. pickletools can disassemble or optimize opcodes without executing them, but static review is not a complete sandbox. Run migrations from isolated backups with least privilege.
import io
import pickle
import pickletools
payload = pickle.dumps([1, 2], protocol=0)
operations = [opcode.name for opcode, argument, position in pickletools.genops(payload)]
print(operations[0], operations[-1])
print("GLOBAL" in operations) MARK STOP
FalseLocal code tester
Round-trip a trusted object graph
Serialize a small internal value with an explicit protocol and verify shared-reference preservation.
Press Run to load Python locally.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- Python Software Foundationpickle — Python object serializationdocs.python.org
- Python Software Foundationshelve — Python object persistencedocs.python.org
- Python Software Foundationpickletools — Tools for pickle developersdocs.python.org
- Python Software Foundationcopyreg — Register pickle support functionsdocs.python.org
- Python Software FoundationPEP 574 — Pickle protocol 5 with out-of-band datapeps.python.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



