"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'

警告:

  Because the "shelve" module is backed by "pickle", it is insecure to
  load a shelf from an untrusted source.  Like with pickle, loading a
  shelf can execute arbitrary code.

Shelf objects support most of the 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()

   Write back all entries in the cache if the shelf was opened with
   *writeback* set to "True".  Also empty the cache and synchronize
   the persistent dictionary on disk, if feasible.  This is called
   automatically when the shelf is closed with "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
  化された表現) はかなり小さくなければならず、キー衝突が生じた場合に、
  稀にデータベースを更新することができなくなることを意味します。

* The "shelve" module does not support *concurrent* read/write access
  to shelved objects.  (Multiple simultaneous read accesses are safe.)
  When a program has a shelf open for writing, no other program should
  have it open for reading or writing.  Unix file locking can be used
  to solve this, but this differs across Unix versions and requires
  knowledge about the database implementation used.

* 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)

   A subclass of "Shelf" which accepts a *filename* instead of a dict-
   like object.  The underlying file will be opened using
   "dbm.open()".  By default, the file will be created and opened for
   both read and write.  The optional *flag* parameter has the same
   interpretation as for the "open()" function.  The optional
   *protocol* and *writeback* parameters have the same interpretation
   as for the "Shelf" class.


使用例
======

インターフェースは以下のコードに集約されています ("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" モジュール
     Object serialization used by "shelve".
