The pickle module in the Python standard library serializes Python objects into a byte stream and restores them later. Unlike JSON, which only handles basic types, pickle can save and restore almost any Python object: custom classes, nested data structures, functions, and even some compiled code objects.
import pickle
data = {"name": "Maya", "scores": [92, 85, 78], "active": True}
serialized = pickle.dumps(data)
restored = pickle.loads(serialized)
print(restored) # {'name': 'Maya', 'scores': [92, 85, 78], 'active': True}
print(restored == data) # Truepickle.dumps(data) converts the dictionary to bytes. pickle.loads(serialized) reconstructs the original object. The restored object is equal to the original.
Writing pickled objects to a file
Serializing to a string is useful in memory, but most of the time you want the result saved somewhere durable. Use pickle.dump() to serialize an object directly to a binary file instead of building bytes yourself.
import pickle
user = {"id": 42, "name": "Maya", "settings": {"theme": "dark", "notifications": True}}
with open("user.pkl", "wb") as file:
pickle.dump(user, file)The file must be opened in binary write mode ("wb"). Pickle produces bytes, not text. After this code runs, user.pkl contains the serialized dictionary.
Reading pickled objects from a file
Use pickle.load() to deserialize an object from a binary file.
import pickle
with open("user.pkl", "rb") as file:
user = pickle.load(file)
print(user["name"]) # Maya
print(user["settings"]["theme"]) # darkOpen the file in binary read mode ("rb"). pickle.load(file) reads the bytes and reconstructs the exact Python object that was saved.
Pickling custom objects
Pickle can serialize instances of classes you define, as long as the class itself can be imported wherever the data gets loaded back.
class Player:
def __init__(self, name, level, inventory):
self.name = name
self.level = level
self.inventory = inventory
def __repr__(self):
return f"Player({self.name}, level={self.level})"
player = Player("Maya", 14, ["sword", "shield", "potion"])With the Player instance created, save it to a file and load it back the same way you would any other object:
import pickle
with open("savegame.pkl", "wb") as file:
pickle.dump(player, file)
with open("savegame.pkl", "rb") as file:
loaded = pickle.load(file)
print(loaded) # Player(Maya, level=14)
print(loaded.inventory) # ['sword', 'shield', 'potion']Pickle saves the object's dict (its instance attributes) by default. When you load it, Python reconstructs a Player object with the same attributes. The class definition must be importable in the loading script, or pickle will raise an AttributeError.
Pickle protocols
Pickle supports several protocol versions. Higher protocols are more efficient and support more Python features.
import pickle
data = list(range(1000))
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
size = len(pickle.dumps(data, protocol=protocol))
print(f"Protocol {protocol}: {size} bytes")Running this loop over a list of 1000 integers shows how much the output size changes across protocol versions, since each protocol encodes the same data with a different level of compactness:
Protocol 0: 5896 bytes
Protocol 1: 2750 bytes
Protocol 2: 2752 bytes
Protocol 3: 2752 bytes
Protocol 4: 2760 bytes
Protocol 5: 2760 bytesProtocol 0 is the original text-based protocol and produces the largest output by far. Protocol 1 and later use a compact binary format, so the size drops sharply and then stays roughly flat as newer protocols add small framing improvements rather than smaller output.
Always use pickle.HIGHEST_PROTOCOL for new code, since it supports the most Python features. Only use a lower protocol if you need compatibility with older Python versions.
pickle.dump(data, file, protocol=pickle.HIGHEST_PROTOCOL)What pickle can and cannot serialize
Pickle handles most Python objects, but there are important exceptions.
Pickle can serialize:
- Built-in types: None, True, False, integers, floats, complex, strings, bytes, bytearrays
- Collections: tuples, lists, sets, dictionaries
- Instances of user-defined classes
- Functions and classes defined at the top level of a module
Pickle cannot serialize:
- File objects, sockets, and database connections
- Generators and iterators with internal state
- Lambda functions (in most cases)
- Objects that depend on external system state
If you try to pickle an unpicklable object, you get a TypeError:
import pickle
pickle.dumps(open("test.txt", "w"))An open file handle wraps operating system resources that have no meaningful representation as bytes, so pickle refuses the object outright instead of producing broken or misleading output:
TypeError: cannot pickle 'TextIOWrapper' instancesSecurity warning
The most important rule with pickle: never unpickle data from an untrusted source. Pickle can execute arbitrary code during deserialization. An attacker can craft a malicious pickle that runs system commands, deletes files, or exfiltrates data when you call pickle.load.
import pickle
# Dangerous: data from an untrusted API, user upload, or network
# data = request.body
# obj = pickle.loads(data) # DO NOT DO THISPickle is safe for:
- Saving program state to a local file
- Caching computation results for later use
- Sending data between trusted components of the same application
- Checkpointing during long-running tasks
If you need to accept serialized data from external sources, use JSON, CSV files, or a well-defined schema format instead.
Practical example: caching expensive computation
A common safe use of pickle is caching results so you do not repeat expensive work. Load an existing cache from disk if one is already there, and start with an empty dictionary on the first run:
import pickle
from pathlib import Path
cache_path = Path("fibonacci_cache.pkl")
if cache_path.exists():
with open(cache_path, "rb") as file:
cache = pickle.load(file)
else:
cache = {}The fibonacci function checks the cache before doing any recursive work, and every new result gets stored back into the cache dictionary as it is computed:
def fibonacci(n):
if n in cache:
return cache[n]
if n <= 1:
result = n
else:
result = fibonacci(n - 1) + fibonacci(n - 2)
cache[n] = result
return resultCalling the function once populates the cache, and saving it back to disk means the next run of the script can skip straight to the answer instead of recomputing every value:
print(fibonacci(35))
with open(cache_path, "wb") as file:
pickle.dump(cache, file, protocol=pickle.HIGHEST_PROTOCOL)The first run computes Fibonacci numbers and saves the cache. Subsequent runs load the cache and skip the repeated computation. The cache file is trusted because it was created by the same program.
Pickle vs JSON vs CSV
| Feature | pickle | JSON | CSV |
|---|---|---|---|
| Serializes custom classes | Yes | No | No |
| Human-readable | No | Yes | Yes |
| Cross-language | No | Yes | Yes |
| Safe for untrusted input | No | Yes | Yes |
| Output format | Bytes | Text | Text |
| Preserves exact types | Yes | No (loose mapping) | No (all strings) |
Choose pickle when you need to preserve exact Python object state in trusted environments. Choose JSON for APIs, configuration, and cross-language data exchange. Choose CSV for tabular data meant for spreadsheets or data analysis tools.
Common mistakes
Forgetting binary mode. Opening a file with "w" instead of "wb" causes a TypeError because pickle produces bytes, not a string. Always use "wb" for writing and "rb" for reading.
Unpickling untrusted data. This is the most serious pickle mistake. Only unpickle data you created yourself or received from a fully trusted source.
Relying on pickle for long-term storage. Pickle format can change across Python versions. For data you need to read years later, use JSON, CSV, or a database.
Rune AI
Key Insights
- Pickle serializes Python objects to bytes and restores them with full fidelity.
- Use
pickle.dump(obj, file)to write andpickle.load(file)to read. - Use
pickle.dumps(obj)andpickle.loads(data)for in-memory bytes. - Never unpickle data from untrusted sources; pickle can execute arbitrary code.
- Choose the highest protocol version with
protocol=pickle.HIGHEST_PROTOCOLfor best performance. - For cross-language or human-readable needs, prefer JSON or CSV over pickle.
Frequently Asked Questions
Is pickle safe to use?
What is the difference between pickle and JSON?
Can I share pickled data across Python versions?
Conclusion
Pickle is Python's built-in serialization tool for saving and restoring Python objects. Use it for caching, checkpointing, and trusted local storage. Never unpickle data from untrusted sources. When you need cross-language compatibility or human-readable output, use JSON or CSV instead.
More in this topic
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Encode and Decode Base64 Data in Python
Learn how to use Python's base64 module to encode binary data as text and decode Base64 strings back to bytes.