shelve
— Python 物件持久化¶
原始碼: Lib/shelve.py
“shelf” 是一個持久化的、類似字典的物件。與 “dbm” 資料庫的區別在於,shelf 中的值(不是鍵!)可以是任意的 Python 物件——任何 pickle
模組可以處理的物件。這包括大多數類例項、遞迴資料型別以及包含大量共享子物件的物件。鍵是普通的字串。
- shelve.open(filename, flag='c', protocol=None, writeback=False)¶
開啟一個持久化字典。指定的 `filename` 是底層資料庫的基本檔名。作為副作用,可能會向檔名新增副檔名,並且可能會建立多個檔案。預設情況下,底層資料庫檔案以讀寫方式開啟。可選的 `flag` 引數與
dbm.open()
的 `flag` 引數具有相同的解釋。預設情況下,使用
pickle.DEFAULT_PROTOCOL
建立的 pickle 用於序列化值。pickle 協議的版本可以透過 `protocol` 引數指定。由於 Python 語義,shelf 無法知道可變持久化字典條目何時被修改。預設情況下,修改後的物件*僅*在分配給 shelf 時才寫入(參見示例)。如果可選的 `writeback` 引數設定為
True
,則所有訪問過的條目也會快取在記憶體中,並在sync()
和close()
時寫回;這使得在持久化字典中修改可變條目更方便,但是,如果訪問了許多條目,它可能會消耗大量記憶體用於快取,並且它可能會使關閉操作非常慢,因為所有訪問過的條目都被寫回(無法確定哪些訪問過的條目是可變的,也無法確定哪些條目實際被修改過)。3.10 版本中修改:
pickle.DEFAULT_PROTOCOL
現在用作預設的 pickle 協議。3.11 版本中修改: 檔名接受類路徑物件。
備註
不要依賴 shelf 自動關閉;當您不再需要它時,請始終顯式呼叫
close()
,或者將shelve.open()
用作上下文管理器。with shelve.open('spam') as db: db['eggs'] = 'eggs'
Shelf 物件支援字典支援的大多數方法和操作(複製、建構函式以及運算子 |
和 |=
除外)。這使得基於字典的指令碼向需要持久儲存的指令碼的過渡更加容易。
支援另外兩種方法
- Shelf.sync()¶
如果 shelf 以 `writeback` 設定為
True
的方式開啟,則將快取中的所有條目寫回。如果可行,還清空快取並同步磁碟上的持久化字典。當 shelf 透過close()
關閉時,此操作會自動呼叫。
- Shelf.close()¶
同步並關閉持久化的 `dict` 物件。對已關閉的 shelf 進行操作將導致
ValueError
失敗。
參見
持久化字典食譜,具有廣泛支援的儲存格式和原生字典的速度。
限制¶
使用哪個資料庫包(例如
dbm.ndbm
或dbm.gnu
)的選擇取決於可用的介面。因此,直接使用dbm
開啟資料庫是不安全的。資料庫也(不幸地)受限於dbm
的限制(如果使用它)——這意味著儲存在資料庫中的物件(其 pickled 表示)應該相當小,在極少數情況下,鍵衝突可能導致資料庫拒絕更新。shelve
模組不支援對 shelved 物件的*併發*讀/寫訪問。(多個同時讀訪問是安全的。)當一個程式開啟一個 shelf 進行寫入時,不應有其他程式開啟它進行讀取或寫入。可以使用 Unix 檔案鎖定來解決這個問題,但這在不同的 Unix 版本之間有所不同,並且需要了解所使用的資料庫實現。在 macOS 上,
dbm.ndbm
在更新時可能會悄悄地破壞資料庫檔案,這可能導致在嘗試從資料庫讀取時發生嚴重崩潰。
- class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')¶
collections.abc.MutableMapping
的子類,它將 pickled 值儲存在 `dict` 物件中。預設情況下,使用
pickle.DEFAULT_PROTOCOL
建立的 pickle 用於序列化值。pickle 協議的版本可以透過 `protocol` 引數指定。有關 pickle 協議的討論,請參閱pickle
文件。如果 `writeback` 引數為
True
,則物件將保留所有訪問過的條目的快取,並在同步和關閉時將其寫回 `dict`。這允許對可變條目進行自然操作,但可能會消耗更多記憶體並使同步和關閉花費很長時間。`keyencoding` 引數是用於在鍵與底層字典一起使用之前對其進行編碼的編碼。
Shelf
物件也可以用作上下文管理器,在這種情況下,它將在with
塊結束時自動關閉。3.2 版本中修改: 添加了 `keyencoding` 引數;以前,鍵總是以 UTF-8 編碼。
3.4 版本中修改: 添加了上下文管理器支援。
3.10 版本中修改:
pickle.DEFAULT_PROTOCOL
現在用作預設的 pickle 協議。
- class shelve.BsdDbShelf(dict, protocol=None, writeback=False, keyencoding='utf-8')¶
Shelf
的子類,它公開了first()
、next()
、previous()
、last()
和set_location()
方法。這些方法在第三方bsddb
模組(來自 pybsddb)中可用,但在其他資料庫模組中不可用。傳遞給建構函式的 `dict` 物件必須支援這些方法。這通常透過呼叫bsddb.hashopen()
、bsddb.btopen()
或bsddb.rnopen()
中的一個來實現。可選的 `protocol`、`writeback` 和 `keyencoding` 引數與Shelf
類具有相同的解釋。
- class shelve.DbfilenameShelf(filename, flag='c', protocol=None, writeback=False)¶
Shelf
的子類,它接受 `filename` 而不是類似字典的物件。底層檔案將使用dbm.open()
開啟。預設情況下,檔案將以讀寫方式建立和開啟。可選的 `flag` 引數與open()
函式具有相同的解釋。可選的 `protocol` 和 `writeback` 引數與Shelf
類具有相同的解釋。
示例¶
總結一下介面(key
是字串,data
是任意物件)
import shelve
d = shelve.open(filename) # open -- file may get suffix added by low-level
# library
d[key] = data # store data at key (overwrites old data if
# using an existing key)
data = d[key] # retrieve a COPY of data at key (raise KeyError
# if no such key)
del d[key] # delete data stored at key (raises KeyError
# if no such key)
flag = key in d # true if the key exists
klist = list(d.keys()) # a list of all existing keys (slow!)
# as d was opened WITHOUT writeback=True, beware:
d['xx'] = [0, 1, 2] # this works as expected, but...
d['xx'].append(3) # *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!
# having opened d without writeback=True, you need to code carefully:
temp = d['xx'] # extracts the copy
temp.append(5) # mutates the copy
d['xx'] = temp # stores the copy right back, to persist it
# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.
d.close() # close it