The shelve module provides a persistent dictionary backed by a database. Store any picklable Python object with simple key-value access.
Basic Usage
import shelve
# Open (creates files if not exist)
with shelve.open('mydata') as db:
db['user'] = {'name': 'Alice', 'age': 30}
db['scores'] = [95, 87, 92]
db['config'] = {'debug': True}
# Later, retrieve data
with shelve.open('mydata') as db:
print(db['user']) # {'name': 'Alice', 'age': 30}
print(db['scores']) # [95, 87, 92]Dict-Like Operations
import shelve
with shelve.open('mydata') as db:
# Check existence
if 'user' in db:
print("User exists")
# Get with default
value = db.get('missing', 'default')
# Delete
del db['old_key']
# Iterate keys
for key in db:
print(key, db[key])
# Get all keys
keys = list(db.keys())Writeback Mode
By default, modifications to mutable values aren't saved:
import shelve
# Problem: mutations not persisted
with shelve.open('mydata') as db:
db['list'] = [1, 2, 3]
db['list'].append(4) # NOT saved!
with shelve.open('mydata') as db:
print(db['list']) # [1, 2, 3] - append was lost
# Solution 1: reassign
with shelve.open('mydata') as db:
items = db['list']
items.append(4)
db['list'] = items # Explicit reassignment
# Solution 2: writeback=True
with shelve.open('mydata', writeback=True) as db:
db['list'].append(4) # Automatically tracked
# Changes saved on closeWarning: writeback=True caches everything in memory. Use for small datasets.
Sync and Close
import shelve
db = shelve.open('mydata')
try:
db['key'] = 'value'
db.sync() # Force write to disk
# ... more operations
finally:
db.close() # Always close
# Better: use context manager
with shelve.open('mydata') as db:
db['key'] = 'value'
# Auto-synced and closedWhat Can Be Stored
Any picklable Python object:
import shelve
from datetime import datetime
from dataclasses import dataclass
@dataclass
class User:
name: str
email: str
with shelve.open('mydata') as db:
# Primitives
db['count'] = 42
db['name'] = 'Alice'
# Collections
db['items'] = [1, 2, 3]
db['mapping'] = {'a': 1, 'b': 2}
# Objects
db['user'] = User('Alice', 'alice@example.com')
db['timestamp'] = datetime.now()Not storable: lambdas, open files, sockets, generators.
Practical Examples
Simple Cache
import shelve
import hashlib
def cached_fetch(url: str) -> str:
cache_key = hashlib.md5(url.encode()).hexdigest()
with shelve.open('cache') as cache:
if cache_key in cache:
return cache[cache_key]
# Fetch and cache
import urllib.request
content = urllib.request.urlopen(url).read().decode()
cache[cache_key] = content
return contentSession Storage
import shelve
import uuid
class SessionStore:
def __init__(self, path='sessions'):
self.path = path
def create(self, data: dict) -> str:
session_id = str(uuid.uuid4())
with shelve.open(self.path) as db:
db[session_id] = data
return session_id
def get(self, session_id: str) -> dict | None:
with shelve.open(self.path) as db:
return db.get(session_id)
def delete(self, session_id: str):
with shelve.open(self.path) as db:
if session_id in db:
del db[session_id]
sessions = SessionStore()
sid = sessions.create({'user': 'alice', 'role': 'admin'})
print(sessions.get(sid))Config Persistence
import shelve
class Config:
def __init__(self, path='config'):
self.path = path
def get(self, key: str, default=None):
with shelve.open(self.path) as db:
return db.get(key, default)
def set(self, key: str, value):
with shelve.open(self.path) as db:
db[key] = value
def all(self) -> dict:
with shelve.open(self.path) as db:
return dict(db)
config = Config()
config.set('theme', 'dark')
config.set('font_size', 14)
print(config.all())shelve vs Alternatives
| Feature | shelve | sqlite3 | pickle | json |
|---|---|---|---|---|
| Dict-like API | ✓ | ✗ | ✗ | ✗ |
| Query support | ✗ | ✓ | ✗ | ✗ |
| Python objects | ✓ | Limited | ✓ | Limited |
| Human readable | ✗ | ✗ | ✗ | ✓ |
| Concurrent safe | ✗ | ✓ | ✗ | ✗ |
Use shelve when:
- Simple key-value storage
- Storing Python objects
- Single-process access
- Quick prototyping
Use sqlite when:
- Need queries
- Multiple processes
- Large datasets
- Structured data
Limitations
# Keys must be strings
db[123] = 'value' # Error!
db['123'] = 'value' # OK
# Not thread/process safe without external locking
# Use sqlite3 for concurrent access
# Creates multiple files
# mydata.db, mydata.dir, mydata.bak (varies by platform)Quick Reference
import shelve
# Open
db = shelve.open('filename')
db = shelve.open('filename', flag='c') # Create if needed (default)
db = shelve.open('filename', flag='r') # Read-only
db = shelve.open('filename', flag='n') # New (truncate)
db = shelve.open('filename', writeback=True) # Track mutations
# Operations
db['key'] = value # Store
value = db['key'] # Retrieve
del db['key'] # Delete
'key' in db # Check
db.keys() # All keys
db.sync() # Force write
db.close() # Close
# Context manager (recommended)
with shelve.open('filename') as db:
db['key'] = valueshelve is the simplest persistence for Python objects. When you outgrow it, move to sqlite3 or a proper database.
React to this post: