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

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

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

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

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

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

   デフォルトでは、値を整列化する際にはバージョン 0 の pickle 化が用い
   られます。pickle 化プロトコルのバージョンは *protocol* パラメータで
   指定することができます。pickle 化プロトコルについては "pickle" のド
   キュメントを参照してください。

   バージョン 2.3 で変更: *protocol* パラメータが追加されました。

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

   ファイルオブジェクト同様に、shelve オブジェクトは永続データが確実に
   ディスクにフラッシュされるように、明示的にクローズすべきです。

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

シェルフオブジェクトは辞書がサポートするほとんどのメソッドをサポートし
ています。これにより、辞書ベースのスクリプトから永続的な記憶媒体を必要
とするスクリプトに容易に移行できるようになります。

Python 3 への移行用メソッド ("viewkeys()", "viewvalues()",
"viewitems()") はサポートされていないことに注意してください。

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

Shelf.sync()

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

Shelf.close()

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

参考: 通常の辞書に近い速度をもち、いろいろなストレージフォーマットに
  対応し た、 永続化辞書のレシピ 。


11.4.1. 制限事項
================

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

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

class shelve.Shelf(dict, protocol=None, writeback=False)

   "UserDict.DictMixin" のサブクラスで、pickle 化された値を *dict* オ
   ブジェクトに保存します。

   デフォルトでは、値を整列化する際にはバージョン 0 の pickle 化が用い
   られます。pickle 化プロトコルのバージョンは *protocol* パラメータで
   指定することができます。pickle 化プロトコルについては "pickle" のド
   キュメントを参照してください。

   バージョン 2.3 で変更: *protocol* パラメータが追加されました。

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

class shelve.BsdDbShelf(dict, protocol=None, writeback=False)

   "Shelf" のサブクラスで、 "first()", "next()", "previous()",
   "last()", "set_location()" メソッドを公開しています。これらのメソッ
   ドは "bsddb" モジュールでは利用可能ですが、他のデータベースモジュー
   ルでは利用できません。コンストラクタに渡された *dict* オブジェクト
   は上記のメソッドをサポートしていなくてはなりません。通常は、
   "bsddb.hashopen()", "bsddb.btopen()" または "bsddb.rnopen()" のいず
   れかを呼び出して得られるオブジェクトが条件を満たしています。オプシ
   ョンの *protocol* および *writeback* パラメタは "Shelf" クラスにお
   けるパラメタと同様に解釈されます。

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

   "Shelf" のサブクラスで、辞書に似たオブジェクトの代わりに *filename*
   を受理します。根底にあるファイルは "anydbm.open()" を使って開かれま
   す。デフォルトでは、ファイルは読み書き可能な状態で開かれます。オプ
   ションの *flag* パラメータは "open()" 関数におけるパラメータと同様
   に解釈されます。オプションの *protocol* および *writeback* パラメー
   タは "Shelf" クラスにおけるパラメータと同様に解釈されます。


11.4.2. 例
==========

インタフェースは以下のコードに集約されています ("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 = d.has_key(key)   # true if the key exists
   klist = d.keys() # a list of all existing keys (slow!)

   # as d was opened WITHOUT writeback=True, beware:
   d['xx'] = range(4)  # this works as expected, but...
   d['xx'].append(5)   # *this doesn't!* -- d['xx'] is STILL range(4)!

   # 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

参考:

  "anydbm" モジュール
     "dbm" スタイルの汎用的なインタフェース

  "bsddb" モジュール
     BSD "db" データベースインタフェース。

  "dbhash" モジュール
     "bsddb" をラップする薄いレイヤで、他のデータベースモジュールのよ
     うに関数 "open()" を提供しています。

  "dbm" モジュール
     標準の Unix データベースインタフェース。

  "dumbdbm" モジュール
     "dbm" インタフェースの移植性のある実装。

  "gdbm" モジュール
     "dbm" インタフェースに基づいた GNU データベースインタフェース。

  "pickle" モジュール
     "shelve" によって使われるオブジェクト整列化機構。

  "cPickle" モジュール
     "pickle" の高速版。
