"shelve" --- Python オブジェクトの永続化
****************************************

**ソースコード:** Lib/shelve.py

======================================================================

"シェルフ (shelf, 棚)" は辞書に似た永続性を持つオブジェクトです。
"dbm" データベースとの違いは、シェルフの値 (キーではありません！) は実
質上どんな Python オブジェクトにも --- "pickle" モジュールが扱えるなら
何でも --- できるということです。これにはほとんどのクラスインスタンス
、再帰的なデータ型、沢山の共有されたサブオブジェクトを含むオブジェクト
が含まれます。キーは通常の文字列です。

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

   永続的な辞書を開きます。指定された *filename* は、根底にあるデータ
   ベースの基本ファイル名となります。副作用として、 *filename* には拡
   張子がつけられる場合があり、ひとつ以上のファイルが生成される可能性
   もあります。デフォルトでは、根底にあるデータベースファイルは読み書
   き可能なように開かれます。オプションの *flag* パラメータは
   "dbm.open()" における *flag* パラメータと同様に解釈されます。

   By default, pickles created with "pickle.DEFAULT_PROTOCOL" are used
   to serialize values.  The version of the pickle protocol can be
   specified with the *protocol* parameter.

   Python の意味論により、シェルフには永続的な辞書の可変エントリがいつ
   変更されたかを知る術がありません。 デフォルトでは、変更されたオブジ
   ェクトはシェルフに代入されたとき *だけ* 書き込まれます (使用例 参照
   )。 オプションの *writeback* パラメータが  "True" に設定されている
   場合は、アクセスされたすべてのエントリはメモリ上にキャッシュされ、
   "sync()" および "close()" を呼び出した際に書き戻されます; この機能
   は永続的な辞書上の可変の要素に対する変更を容易にしますが、多数のエ
   ントリがアクセスされた場合、膨大な量のメモリがキャッシュのために消
   費され、アクセスされた全てのエントリを書き戻す (アクセスされたエン
   トリが可変であるか、あるいは実際に変更されたかを決定する方法は存在
   しないのです) ために、ファイルを閉じる操作が非常に低速になります。

   バージョン 3.10 で変更: "pickle.DEFAULT_PROTOCOL" is now used as
   the default pickle protocol.

   バージョン 3.11 で変更: Accepts *path-like object* for filename.

   注釈:

     シェルフが自動的に閉じることに依存しないでください; それがもう必
     要ない場合は常に "close()" を明示的に呼ぶか、 "shelve.open()" を
     コンテキストマネージャとして使用してください:

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

警告:

  "shelve" モジュールは裏で "pickle" を使っているので、信頼できないソ
  ースからシェルフを読み込むのは危険です。 pickle と同じく、 shelf の
  読み込みでも任意のコードを実行できるからです。

Shelf objects support most of methods and operations supported by
dictionaries (except copying, constructors and operators "|" and
"|=").  This eases the transition from dictionary based scripts to
those requiring persistent storage.

追加でサポートされるメソッドが二つあります:

Shelf.sync()

   シェルフが *writeback* を "True" にセットして開かれている場合に、キ
   ャッシュ中の全てのエントリを書き戻します。また可能な場合は、キャッ
   シュを空にしてディスク上の永続的な辞書を同期します。このメソッドは
   シェルフを "close()" によって閉じるとき自動的に呼び出されます。

Shelf.close()

   永続的な *辞書* オブジェクトを同期して閉じます。既に閉じられている
   シェルフに対して呼び出すと "ValueError" を出し失敗します。

参考:

  Persistent dictionary recipe with widely supported storage formats
  and having the speed of native dictionaries.


制限事項
========

* どのデータベースパッケージが使われるか (例えば "dbm.ndbm" 、
  "dbm.gnu") は、どのインターフェースが利用可能かに依存します。従って
  、データベースを "dbm"  を使って直接開く方法は安全ではありません。デ
  ータベースはまた、 "dbm" が使われた場合 (不幸なことに) その制約に縛
  られます --- これはデータベースに記録されたオブジェクト (の pickle
  化された表現) はかなり小さくなければならず、キー衝突が生じた場合に、
  稀にデータベースを更新することができなくなることを意味します。

* "shelve" モジュールは、シェルフに置かれたオブジェクトの *並列した*
  読み出し/書き込みアクセスをサポートしません (複数の同時読み出しアク
  セスは安全です)。あるプログラムが書き込みのために開かれたシェルフを
  持っているとき、他のプログラムはそのシェルフを読み書きのために開いて
  はいけません。この問題を解決するために Unix のファイルロック機構を使
  うことができますが、この機構は Unix のバージョン間で異なり、使われて
  いるデータベースの実装について知識が必要となります。

* On macOS "dbm.ndbm" can silently corrupt the database file on
  updates, which can cause hard crashes when trying to read from the
  database.

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

   "collections.abc.MutableMapping" のサブクラスで、 *dict* オブジェク
   ト内にpickle化された値を保持します。

   By default, pickles created with "pickle.DEFAULT_PROTOCOL" are used
   to serialize values.  The version of the pickle protocol can be
   specified with the *protocol* parameter.  See the "pickle"
   documentation for a discussion of the pickle protocols.

   *writeback* パラメータが "True" に設定されていれば、アクセスされた
   すべてのエントリはメモリ上にキャッシュされ、ファイルを閉じる際に
   *dict* に書き戻されます; この機能により、可変のエントリに対して自然
   な操作が可能になりますが、さらに多くのメモリを消費し、辞書をファイ
   ルと同期して閉じる際に長い時間がかかるようになります。

   *keyencoding* パラメータは、shelf の背後にある dict に対して使われ
   る前にキーをエンコードするのに使用されるエンコーディングです。

   "Shelf" オブジェクトは、コンテキストマネージャとしても使用できます
   。この場合、 "with" ブロックが終了する際に、自動的に閉じられます。

   バージョン 3.2 で変更: *keyencoding* パラメータを追加; 以前はキーは
   常に UTF-8 でエンコードされていました。

   バージョン 3.4 で変更: コンテキストマネージャーサポートが追加されま
   した。

   バージョン 3.10 で変更: "pickle.DEFAULT_PROTOCOL" is now used as
   the default pickle protocol.

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

   A subclass of "Shelf" which exposes "first()", "next()",
   "previous()", "last()" and "set_location()" methods. These are
   available in the third-party "bsddb" module from pybsddb but not in
   other database modules.  The *dict* object passed to the
   constructor must support those methods.  This is generally
   accomplished by calling one of "bsddb.hashopen()", "bsddb.btopen()"
   or "bsddb.rnopen()".  The optional *protocol*, *writeback*, and
   *keyencoding* parameters have the same interpretation as for the
   "Shelf" class.

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" によって使われるオブジェクト整列化機構。
