當專案需要儲存簡單的鍵值資料,但又不想引入 SQLite、Redis 等資料庫時,Python 標準庫中的 shelve 模組是極佳選擇。它以 dbm 為後端,提供類字典介面,支援任意可序列化物件(透過 pickle),幾行代碼即可實現資料持久化。
import shelve
# 開啟/建立資料庫檔案(會產生 .dat、.dir、.bak 等檔案)
with shelve.open('mydata') as db:
# 寫入:鍵必須為字串,值可為任何可 pickle 的物件
db['user:1001'] = {'name': 'Alice', 'age': 30, 'tags': ['vip', 'beta']}
db['settings'] = {'theme': 'dark', 'lang': 'zh-TW'}
# 讀取
print(db['user:1001']) # {'name': 'Alice', 'age': 30, ...}
print(db.get('nonexist', '預設值')) # 安全取值
# 遍歷
for k, v in db.items():
print(k, '->', v)
# 刪除
del db['settings']
預設情況下,對取出的可變物件修改不會自動存回磁碟。
with shelve.open('test') as db:
db['list'] = [1, 2, 3]
lst = db['list']
lst.append(4) # 記憶體中已變 [1,2,3,4]
# db['list'] 仍為 [1,2,3] 除非顯式回寫或啟用 writeback
解決方式:
db['list'] = lstshelve.open('test', writeback=True)。會快取所有讀取物件,關閉時一次寫回。缺點:記憶體佔用大、關閉慢、若程式異常終止可能遺失資料。shelve 不支援多執行緒/多進程並發寫入。若有並發需求,請自行加鎖(threading.Lock 或檔案鎖),或改用 SQLite / Redis。
務必呼叫 close() 或使用 with 區塊,確保資料刷新至磁碟。
#!/usr/bin/env python3
import shelve
import sys
DB_PATH = 'contacts.db'
def add_contact(db):
cid = input('ID: ').strip()
if cid in db:
print('ID 已存在')
return
db[cid] = {
'name': input('姓名: ').strip(),
'phone': input('電話: ').strip(),
'email': input('Email: ').strip()
}
print('新增完成')
def find_contact(db):
cid = input('查詢 ID: ').strip()
info = db.get(cid)
if info:
for k, v in info.items():
print(f'{k}: {v}')
else:
print('查無此人')
def list_all(db):
if not db:
print('通訊錄為空')
return
for cid, info in db.items():
print(f"[{cid}] {info['name']} - {info['phone']}")
def main():
with shelve.open(DB_PATH) as db:
actions = {
'1': ('新增', add_contact),
'2': ('查詢', find_contact),
'3': ('列出全部', list_all),
'q': ('離開', None)
}
while True:
print('\n=== 通訊錄 ===')
for k, (desc, _) in actions.items():
print(f'{k}. {desc}')
cmd = input('選擇: ').strip().lower()
if cmd == 'q':
break
if cmd in actions:
actions[cmd][1](db)
else:
print('無效指令')
if __name__ == '__main__':
main()
| 優點 | 缺點/限制 | 適用場景 |
|---|---|---|
| 零依賴、標準庫即用 API 簡單(dict-like) 支援任意 Python 物件 |
無並發保護 大量資料時效能差(全量 pickle) 無索引、查詢只能全掃 資料庫損壞風險較高(單檔) |
配置檔持久化 小型應用快取 單用戶桌面工具 測試/原型階段資料存儲 |
一言以蔽之:shelve 是「帶持久化的 dict」,適合資料量小、結構簡單、無並發的場合;超出此範圍請轉向 SQLite 或專業資料庫。