shelve — Python 物件持久化

原始碼: Lib/shelve.py


“shelf” 是一個持久化的、類似字典的物件。與“dbm”資料庫的區別在於 shelf 中的值(而不是鍵!)本質上可以是任意 Python 物件 —— 任何 pickle 模組可以處理的物件。這包括大多數類例項、遞迴資料型別以及包含許多共享子物件的物件。鍵是普通的字串。

shelve.open(filename, flag='c', protocol=None, writeback=False)

開啟一個持久化的字典。指定的 filename 是底層資料庫的基本檔名。作為副作用,可以向 filename 新增副檔名,並且可以建立多個檔案。預設情況下,底層資料庫檔案以讀寫模式開啟。可選的 flag 引數的解釋與 dbm.open()flag 引數相同。

預設情況下,使用 pickle.DEFAULT_PROTOCOL 建立的 pickle 用於序列化值。可以使用 protocol 引數指定 pickle 協議的版本。

由於 Python 語義,shelf 無法知道何時修改了可變持久字典條目。預設情況下,修改後的物件在分配給 shelf 時才會被寫入(請參閱 示例)。如果可選的 writeback 引數設定為 True,則所有訪問的條目也會快取在記憶體中,並在 sync()close() 時寫回;這可以更方便地在持久字典中修改可變條目,但是,如果訪問了許多條目,它可能會消耗大量記憶體用於快取,並且由於所有訪問的條目都會被寫回(無法確定哪些訪問的條目是可變的,也無法確定哪些條目實際上被修改了),因此關閉操作可能會非常慢。

在 3.10 版本中變更: pickle.DEFAULT_PROTOCOL 現在用作預設的 pickle 協議。

在 3.11 版本中變更: 接受 filename 的 路徑類物件

注意

不要依賴於 shelf 自動關閉;當你不再需要它時,總是顯式呼叫 close(),或者使用 shelve.open() 作為上下文管理器

with shelve.open('spam') as db:
    db['eggs'] = 'eggs'

警告

由於 shelve 模組由 pickle 支援,因此從不受信任的來源載入 shelf 是不安全的。就像 pickle 一樣,載入 shelf 可以執行任意程式碼。

Shelf 物件支援字典支援的大多數方法和操作(除了複製、建構函式和運算子 ||=)。這簡化了從基於字典的指令碼到需要持久化儲存的指令碼的過渡。

支援兩個額外的方法

Shelf.sync()

如果 shelf 在開啟時將 writeback 設定為 True,則寫回快取中的所有條目。如果可行,也清空快取並將持久字典同步到磁碟。當使用 close() 關閉 shelf 時,會自動呼叫此方法。

Shelf.close()

同步並關閉持久化的 dict 物件。對已關閉的 shelf 進行操作將會失敗並丟擲 ValueError 異常。

另請參閱

持久化字典配方,該配方具有廣泛支援的儲存格式,並且具有本機字典的速度。

限制

  • 將使用哪個資料庫包(例如 dbm.ndbmdbm.gnu)的選擇取決於哪個介面可用。因此,使用 dbm 直接開啟資料庫是不安全的。如果使用了 dbm,則資料庫也(不幸地)會受到 dbm 的限制——這意味著儲存在資料庫中的物件(的 pickle 表示形式)應該相當小,並且在極少數情況下,鍵衝突可能會導致資料庫拒絕更新。

  • shelve 模組不支援對 shelf 物件進行併發讀/寫訪問。(多個同時讀取訪問是安全的。)當程式開啟一個 shelf 進行寫入時,其他程式不應開啟它進行讀取或寫入。可以使用 Unix 檔案鎖定來解決此問題,但這在不同的 Unix 版本中有所不同,並且需要了解所使用的資料庫實現。

  • 在 macOS 上,dbm.ndbm 可以在更新時靜默損壞資料庫檔案,這可能會在嘗試從資料庫讀取時導致硬崩潰。

class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')

collections.abc.MutableMapping 的子類,它將 pickle 的值儲存在 dict 物件中。

預設情況下,使用 pickle.DEFAULT_PROTOCOL 建立的 pickle 用於序列化值。可以使用 protocol 引數指定 pickle 協議的版本。有關 pickle 協議的討論,請參閱 pickle 文件。

如果 writeback 引數為 True,則物件將儲存所有訪問的條目的快取,並在同步和關閉時將它們寫回到 dict。這允許對可變條目進行自然操作,但會消耗更多記憶體,並使同步和關閉花費很長時間。

keyencoding 引數是用於在將鍵與底層 dict 一起使用之前對其進行編碼的編碼。

一個 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() 之一來實現。可選的 protocolwritebackkeyencoding 引數與 Shelf 類的解釋相同。

class shelve.DbfilenameShelf(filename, flag='c', protocol=None, writeback=False)

Shelf 的子類,它接受一個 filename 而不是類似 dict 的物件。底層檔案將使用 dbm.open() 開啟。預設情況下,該檔案將被建立並開啟以進行讀取和寫入。可選的 flag 引數與 open() 函式的解釋相同。可選的 protocolwriteback 引數與 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

另請參閱

模組 dbm

dbm 風格資料庫的通用介面。

模組 pickle

shelve 使用的物件序列化。