pyguides

shelve module

Overview

shelve provides a simple way to persist Python objects to disk. It behaves like a dictionary but stores its contents in a file (or set of files) that persists between program runs. Keys must be strings; values can be any object that pickle can serialize.

Under the hood, shelve uses pickle to serialize objects and dbm to store them. The shelf acts as a persistent dictionary — you read and write to it just like a regular dict, and the data survives after the program exits.

Opening a Shelf

import shelve

# Open (create if doesn't exist, read/write mode)
db = shelve.open("my_data")

# Equivalent to:
db = shelve.open("my_data", flag="c")  # c = create/read/write

The flag parameter controls how the shelf is opened:

FlagMeaning
"r"Open existing shelf for reading only
"w"Open existing shelf for reading and writing
"c"Create if doesn’t exist; open existing for read/write (default)
"n"Always create a new empty shelf; fails if it exists
# Read-only
db = shelve.open("existing_data", flag="r")

# Always start fresh
db = shelve.open("new_data", flag="n")

Reading and Writing

import shelve

db = shelve.open("config")

# Store values (any pickle-serializable object)
db["name"] = "Alice"
db["preferences"] = {"theme": "dark", "notifications": True}
db["scores"] = [95, 87, 92, 88]

# Read like a dictionary
print(db["name"])  # Alice
print(db["preferences"])  # {'theme': 'dark', 'notifications': True}

db.close()

Use the shelf as a context manager for automatic closing:

with shelve.open("config") as db:
    db["last_login"] = "2026-04-21"
    print(db["last_login"])
# Shelf is closed automatically

Keys Must Be Strings

Shelf keys must be strings (this is a dbm limitation, not a Python dict limitation):

with shelve.open("data") as db:
    db["string_key"] = "value"
    # db[123] = "value"  # TypeError: keys must be strings

    # Common workaround: convert int keys to strings
    key = 123
    db[str(key)] = "numeric key as string"

The protocol Parameter

By default, shelve uses the highest protocol available for your Python version (currently protocol 5 in Python 3.8+). You can specify a protocol explicitly:

# Use a specific protocol
db = shelve.open("data", protocol=4)

# Protocol 4: Python 3.4+, supports out-of-band buffers
# Protocol 3: Python 3.0+, not compatible with Python 2
# Protocol 2: Python 2.3+, wider compatibility

In most cases, protocol=None (the default) is what you want — it uses pickle.DEFAULT_PROTOCOL, which is the highest available.

The writeback Flag — Caching Behaviour

By default, writeback=False. The shelf only writes data when you assign to it. This is memory-efficient but means mutations to mutable objects inside the shelf aren’t saved automatically:

db = shelve.open("data")
db["list"] = [1, 2, 3]

temp = db["list"]
temp.append(4)
# db["list"] is still [1, 2, 3] — temp is a *copy*, not a reference

db["list"] = temp  # Must reassign to persist
db.close()

Set writeback=True to automatically track mutations:

db = shelve.open("data", writeback=True)
db["list"] = [1, 2, 3]

db["list"].append(4)  # Now this *does* persist
db.close()  # Writes everything back to disk

The trade-off: writeback=True consumes more memory (it caches every accessed item) and makes close() slower (it syncs everything). Use it only when you frequently mutate nested objects.

To sync the cache without closing:

db = shelve.open("data", writeback=True)
db["counter"] = 0

for i in range(100):
    db["counter"] += 1

db.sync()  # Write changes to disk, keep shelf open

Closing and Syncing

Always close the shelf to ensure data is written to disk:

db = shelve.open("data")
db["key"] = "value"
db.close()

Or use the context manager:

with shelve.open("data") as db:
    db["key"] = "value"
# Automatically closed

Explicitly sync to flush cached writes without closing:

db["key"] = "value"
db.sync()  # Force write to disk
db["key"] = "other"
db.close()  # Final close

Deleting and Checking Keys

with shelve.open("data") as db:
    db["name"] = "Alice"
    db["age"] = 30

    # Check if key exists
    print("name" in db)  # True

    # Delete a key
    del db["age"]

    # Get with default (like dict)
    print(db.get("name", "default"))  # Alice
    print(db.get("missing", "default"))  # default

Iterating Over a Shelf

with shelve.open("data") as db:
    db["a"] = 1
    db["b"] = 2
    db["c"] = 3

    # Keys
    for key in db:
        print(key)

    # Keys and values
    for key, value in db.items():
        print(f"{key}: {value}")

Common Pitfalls

Shelf files are not human-readable. Unlike JSON or CSV, a shelf file is binary. Don’t try to open it in a text editor. Use a new shelve.open() call to read its contents.

Platform-specific format. The underlying dbm library produces different file formats on different operating systems. A shelf created on Linux won’t necessarily open on Windows.

Keys must be strings. This catches many people coming from regular Python dicts:

db[42] = "value"  # TypeError: keys must be strings

Mutations aren’t auto-saved. As described above, modifying a mutable object retrieved from the shelf doesn’t change the stored value unless you reassign it.

See Also