\section{\module{shelve} ---
         Python オブジェクトの永続化}

\declaremodule{standard}{shelve}
\modulesynopsis{Python オブジェクトの永続化。}


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

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

デフォルトでは、値を整列化する際にはバージョン 0 の pickle 化が
用いられます。pickle 化プロトコルのバージョンは \var{protocol}
パラメタで指定することができます。\versionchanged[\var{protocol}
パラメタが追加されました。]{2.3}

デフォルトでは、永続的な辞書の可変エントリに対する変更をおこなっても、
自動的にファイルには書き戻されません。オプションの \var{writeback}
パラメタが {}\var{True} に設定されていれば、アクセスされたすべての
エントリはメモリ上にキャッシュされ、ファイルを閉じる際に書き戻されます;
この機能は永続的な辞書上の可変の要素に対する変更を容易にしますが、
多数のエントリがアクセスされた場合、膨大な量のメモリがキャッシュの
ために消費され、アクセスされた全てのエントリを書き戻す (アクセスされた
エントリが可変であるか、あるいは実際に変更されたかを決定する方法は
存在しないのです) ために、ファイルを閉じる操作を非常に低速にしてしまいます。
\end{funcdesc}

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

もう一つ追加でサポートされるメソッドがあります。
\begin{methoddesc}[Shelf]{sync}{}
シェルフが \var{writeback} を \var{True} にセットして開かれている場合に、
キャッシュ中の全てのエントリを書き戻します。また容易にできるならば、
キャッシュを空にしてディスク上の永続的な辞書を同期します。このメソッドは
シェルフを \method{close()} によって閉じるとき自動的に呼び出されます。
\end{methoddesc}
  
\subsection{制限事項}
  
  \begin{itemize}
  
  \item
どのデータベースパッケージが使われるか (例えば \refmodule{dbm}、
\refmodule{gdbm}、\refmodule{bsddb}) は、どのインタフェースが
利用可能かに依存します。従って、データベースを \refmodule{dbm} 
を使って直接開く方法は安全ではありません。データベースはまた、
\refmodule{dbm} が使われた場合
(不幸なことに) その制約に縛られます --- これはデータベースに
記録されたオブジェクト (の pickle 化された表現) はかなり小さく
なければならず、キー衝突が生じた場合に、稀にデータベースを更新
することができなくなるということを意味します。
\refbimodindex{dbm}
\refbimodindex{gdbm}
\refbimodindex{bsddb}
  
\item
実装に依存して、永続化した辞書を閉じるときには、変更がディスクに
書き込まれるかもしれないし、必ずしも書き込まれないかもしれません。
\class{Shelf} クラスの \method{__del__} メソッドは \method{close}
メソッドを呼び出すので、プログラマは通常この作業を明示的に行う必要は
ありません。
  
\item
\module{shelve} モジュールは、シェルフに置かれたオブジェクトの
\emph{並列した} 読み出し/書き込みアクセスをサポートしません
(複数の同時読み出しアクセスは安全です)。あるプログラムが書き込み
ために開かれたシェルフを持っているとき、他のプログラムは
そのシェルフを読み書きのために開いてはいけません。この問題を
解決するために \UNIX{} のファイルロック機構を使うことができますが、
この機構は \UNIX{} のバージョン間で異なり、使われている
データベースの実装について知識が必要となります。
\end{itemize}

\begin{classdesc}{Shelf}{dict\optional{, protocol=None\optional{, writeback=False}}}
\class{UserDict.DictMixin} のサブクラスで、pickle 化された値を 
\var{dict} オブジェクトに保存します。

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

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

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

\end{classdesc}

\begin{classdesc}{DbfilenameShelf}{filename\optional{, flag='c'\optional{, protocol=None\optional{, writeback=False}}}}
\class{Shelf} のサブクラスで、辞書様オブジェクトの代わりに
\var{filename} を受理します。根底にあるファイルは 
{}\function{anydbm.open} を使って開かれます。デフォルトでは、
ファイルは読み書き可能な状態で開かれます。オプションの \var{flag}
パラメタは \function{open} 関数におけるパラメタと同様に解釈されます。
オプションの \var{protocol}、および \var{writeback} パラメタは
\class{Shelf} クラスにおけるパラメタと同様に解釈されます。
 
\end{classdesc}

\subsection{使用例}

インタフェースは以下のコードに集約されています (\code{key} は文字列で、
\code{data} は任意のオブジェクトです):

\begin{verbatim}
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
\end{verbatim}
  
\begin{seealso}
  \seemodule{anydbm}{\code{dbm} スタイルのデータベースに対する汎用インタフェース。}
  \seemodule{bsddb}{BSD \code{db} データベースインタフェース。}
  \seemodule{dbhash}{\module{bsddb} をラップする薄いレイヤで、他のデータベースモジュールのように関数 \function{open} を提供しています。}
  \seemodule{dbm}{標準の \UNIX{} データベースインタフェース。}
  \seemodule{dumbdbm}{\code{dbm} インタフェースの移植性のある実装。}
  \seemodule{gdbm}{\code{dbm} インタフェースに基づいた GNU データベースインタフェース。}
  \seemodule{pickle}{\module{shelve} によって使われるオブジェクト整列化機構。}
  \seemodule{cPickle}{\refmodule{pickle} の高速版。}
\end{seealso}
