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'

警告

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

Shelf 物件支援字典支援的大多數方法和操作(複製、建構函式以及運算子 ||= 除外)。這使得基於字典的指令碼向需要持久儲存的指令碼的過渡更加容易。

支援另外兩種方法

Shelf.sync()

如果 shelf 以 `writeback` 設定為 True 的方式開啟,則將快取中的所有條目寫回。如果可行,還清空快取並同步磁碟上的持久化字典。當 shelf 透過 close() 關閉時,此操作會自動呼叫。

Shelf.close()

同步並關閉持久化的 `dict` 物件。對已關閉的 shelf 進行操作將導致 ValueError 失敗。

參見

持久化字典食譜,具有廣泛支援的儲存格式和原生字典的速度。

限制

  • 使用哪個資料庫包(例如 dbm.ndbmdbm.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

參見

模組 dbm

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

pickle 模組

shelve 使用的物件序列化。