shelve
--- Python 對象持久化?
源代碼: Lib/shelve.py
"Shelf" 是一種持久化的類(lèi)似字典的對象。 與 "dbm" 數據庫的區別在于 Shelf 中的值(不是鍵?。?shí)際上可以為任意 Python 對象 --- 即 pickle
模塊能夠處理的任何東西。 這包括大部分類(lèi)實(shí)例、遞歸數據類(lèi)型,以及包含大量共享子對象的對象。 鍵則為普通的字符串。
- shelve.open(filename, flag='c', protocol=None, writeback=False)?
打開(kāi)一個(gè)持久化字典。 filename 指定下層數據庫的基準文件名。 作為附帶效果,會(huì )為 filename 添加一個(gè)擴展名并且可能創(chuàng )建更多的文件。 默認情況下,下層數據庫會(huì )以讀寫(xiě)模式打開(kāi)。 可選的 flag 形參具有與
dbm.open()
flag 形參相同的含義。在默認情況下,會(huì )使用以
pickle.DEFAULT_PROTOCOL
創(chuàng )建的 pickle 來(lái)序列化值。 pickle 協(xié)議的版本可通過(guò) protocol 形參來(lái)指定。由于 Python 語(yǔ)義的限制,Shelf 對象無(wú)法確定一個(gè)可變的持久化字典條目在何時(shí)被修改。 默認情況下 只有 在被修改對象再賦值給 shelf 時(shí)才會(huì )寫(xiě)入該對象 (參見(jiàn) 示例)。 如果可選的 writeback 形參設為
True
,則所有被訪(fǎng)問(wèn)的條目都將在內存中被緩存,并會(huì )在sync()
和close()
時(shí)被寫(xiě)入;這可以使得對持久化字典中可變條目的修改更方便,但是如果訪(fǎng)問(wèn)的條目很多,這會(huì )消耗大量?jì)却孀鳛榫彺?,并?huì )使得關(guān)閉操作變得非常緩慢,因為所有被訪(fǎng)問(wèn)的條目都需要寫(xiě)回到字典(無(wú)法確定被訪(fǎng)問(wèn)的條目中哪個(gè)是可變的,也無(wú)法確定哪個(gè)被實(shí)際修改了)。在 3.10 版更改:
pickle.DEFAULT_PROTOCOL
現在會(huì )被用作默認的 pickle 協(xié)議。在 3.11 版更改: Accepts path-like object for filename.
備注
請不要依賴(lài)于 Shelf 的自動(dòng)關(guān)閉功能;當你不再需要時(shí)應當總是顯式地調用
close()
,或者使用shelve.open()
作為上下文管理器:with shelve.open('spam') as db: db['eggs'] = 'eggs'
Shelf 對象支持字典所支持的大多數方法和運算(除了拷貝、構造器以及 |
和 |=
運算符)。 這樣就能方便地將基于字典的腳本轉換為要求持久化存儲的腳本。
額外支持的兩個(gè)方法:
- Shelf.sync()?
如果 Shelf 打開(kāi)時(shí)將 writeback 設為
True
則寫(xiě)回緩存中的所有條目。 如果可行還會(huì )清空緩存并將持久化字典同步到磁盤(pán)。 此方法會(huì )在使用close()
關(guān)閉 Shelf 時(shí)自動(dòng)被調用。
- Shelf.close()?
同步并關(guān)閉持久化 dict 對象。 對已關(guān)閉 Shelf 的操作將失敗并引發(fā)
ValueError
。
參見(jiàn)
持久化字典方案,使用了廣泛支持的存儲格式并具有原生字典的速度。
限制?
可選擇使用哪種數據庫包 (例如
dbm.ndbm
或dbm.gnu
) 取決于支持哪種接口。 因此使用dbm
直接打開(kāi)數據庫是不安全的。 如果使用了dbm
,數據庫同樣會(huì )(不幸地)受限于它 --- 這意味著(zhù)存儲在數據庫中的(封存形式的)對象尺寸應當較小,并且在少數情況下鍵沖突有可能導致數據庫拒絕更新。shelve
模塊不支持對 Shelf 對象的 并發(fā) 讀/寫(xiě)訪(fǎng)問(wèn)。 (多個(gè)同時(shí)讀取訪(fǎng)問(wèn)則是安全的。) 當一個(gè)程序打開(kāi)一個(gè) shelve 對象來(lái)寫(xiě)入時(shí),不應再有其他程序同時(shí)打開(kāi)它來(lái)讀取或寫(xiě)入。 Unix 文件鎖定可被用來(lái)解決此問(wèn)題,但這在不同 Unix 版本上會(huì )存在差異,并且需要有關(guān)所用數據庫實(shí)現的細節知識。
- class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')?
collections.abc.MutableMapping
的一個(gè)子類(lèi),它會(huì )將封存的值保存在 dict 對象中。在默認情況下,會(huì )使用以
pickle.DEFAULT_PROTOCOL
創(chuàng )建的 pickle 來(lái)序列化值。 pickle 協(xié)議的版本可通過(guò) protocol 形參來(lái)指定。 請參閱pickle
文檔來(lái)查看 pickle 協(xié)議的相關(guān)討論。如果 writeback 形參為
True
,對象將為所有訪(fǎng)問(wèn)過(guò)的條目保留緩存并在同步和關(guān)閉時(shí)將它們寫(xiě)回到 dict。 這允許對可變的條目執行自然操作,但是會(huì )消耗更多內存并讓同步和關(guān)閉花費更長(cháng)時(shí)間。keyencoding 形參是在下層字典被使用之前用于編碼鍵的編碼格式。
Shelf
對象還可以被用作上下文管理器,在這種情況下它將在with
語(yǔ)句塊結束時(shí)自動(dòng)被關(guān)閉。在 3.2 版更改: 添加了 keyencoding 形參;之前,鍵總是使用 UTF-8 編碼。
在 3.4 版更改: 添加了上下文管理器支持。
在 3.10 版更改:
pickle.DEFAULT_PROTOCOL
現在會(huì )被用作默認的 pickle 協(xié)議。
- class shelve.BsdDbShelf(dict, protocol=None, writeback=False, keyencoding='utf-8')?
Shelf
的一個(gè)子類(lèi),將first()
,next()
,previous()
,last()
和set_location()
對外公開(kāi),在來(lái)自 pybsddb 的第三方bsddb
模塊中可用,但在其他數據庫模塊中不可用。 傳給構造器的 dict 對象必須支持這些方法。 這通常是通過(guò)調用bsddb.hashopen()
,bsddb.btopen()
或bsddb.rnopen()
之一來(lái)完成的。 可選的 protocol, writeback 和 keyencoding 形參具有與Shelf
類(lèi)相同的含義。
- class shelve.DbfilenameShelf(filename, flag='c', protocol=None, writeback=False)?
Shelf
的一個(gè)子類(lèi),它接受一個(gè) filename 而非字典類(lèi)對象。 下層文件將使用dbm.open()
來(lái)打開(kāi)。 默認情況下,文件將以讀寫(xiě)模式打開(kāi)。 可選的 flag 形參具有與open()
函數相同的含義。 可選的 protocol 和 writeback 形參具有與Shelf
類(lèi)相同的含義。
示例?
對接口的總結如下 (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