mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 23:14:06 +08:00
32 lines
21 KiB
HTML
32 lines
21 KiB
HTML
<div class="body" role="main"><div class="section" id="module-shelve"><h1><span class="yiyi-st" id="yiyi-10">12.3. <a class="reference internal" href="#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal"><span class="pre">shelve</span></code></a> - Python对象持久性</span></h1><p><span class="yiyi-st" id="yiyi-11"><strong>源代码:</strong> <a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/shelve.py">Lib / shelve.py</a></span></p><p><span class="yiyi-st" id="yiyi-12">“shelf”是一个持久的,类似字典的对象。</span><span class="yiyi-st" id="yiyi-13">与“dbm”数据库的区别是,值(而不是键!)</span><span class="yiyi-st" id="yiyi-14">在一个架子上可以是基本上任意的Python对象 - <a class="reference internal" href="pickle.html#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal"><span class="pre">pickle</span></code></a>模块可以处理的任何东西。</span><span class="yiyi-st" id="yiyi-15">这包括大多数类实例,递归数据类型和包含大量共享子对象的对象。</span><span class="yiyi-st" id="yiyi-16">键是普通字符串。</span></p><dl class="function"><dt id="shelve.open"><span class="yiyi-st" id="yiyi-17"> <code class="descclassname">shelve.</code><code class="descname">open</code><span class="sig-paren">(</span><em>filename</em>, <em>flag='c'</em>, <em>protocol=None</em>, <em>writeback=False</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-18">打开持久性字典。</span><span class="yiyi-st" id="yiyi-19">指定的文件名是基础数据库的基本文件名。</span><span class="yiyi-st" id="yiyi-20">作为副作用,可以向文件名添加扩展名,并且可以创建多个文件。</span><span class="yiyi-st" id="yiyi-21">默认情况下,打开底层数据库文件以进行读取和写入。</span><span class="yiyi-st" id="yiyi-22">可选的<em>标志</em>参数与<a class="reference internal" href="dbm.html#dbm.open" title="dbm.open"><code class="xref py py-func docutils literal"><span class="pre">dbm.open()</span></code></a>的<em>标志</em>参数具有相同的解释。</span></p><p><span class="yiyi-st" id="yiyi-23">默认情况下,版本3 pickles 用于序列化值。</span><span class="yiyi-st" id="yiyi-24">可以使用<em>协议</em>参数指定pickle协议的版本。</span></p><p><span class="yiyi-st" id="yiyi-25">由于Python语义,shelf 不能知道何时修改了可变的持久化字典条目。</span><span class="yiyi-st" id="yiyi-26">默认情况下,修改的对象在分配到货架时写入<em></em>(请参阅<a class="reference internal" href="#shelve-example"><span>Example</span></a>)。</span><span class="yiyi-st" id="yiyi-27">如果可选的<em>回写</em>参数设置为<em>True</em>,所有访问的条目也会缓存在内存中,并写回<a class="reference internal" href="#shelve.Shelf.sync" title="shelve.Shelf.sync"><code class="xref py py-meth docutils literal"><span class="pre">sync()</span></code></a>和<a class="reference internal" href="#shelve.Shelf.close" title="shelve.Shelf.close"><code class="xref py py-meth docutils literal"><span class="pre">close()</span></code></a>;这可以使得持久化字典中的可变条目变得更容易,但是,如果访问许多条目,则它可以消耗大量的高速缓存的存储器,并且它可以使得关闭操作非常缓慢,因为所有访问的条目被回写没有办法确定哪些被访问的条目是可变的,哪些被实际上被变异)。</span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-28">注意</span></p><p><span class="yiyi-st" id="yiyi-29">不要依靠架子自动关闭;当你不再需要它时,总是调用<a class="reference internal" href="#shelve.Shelf.close" title="shelve.Shelf.close"><code class="xref py py-meth docutils literal"><span class="pre">close()</span></code></a>,或者使用<a class="reference internal" href="#shelve.open" title="shelve.open"><code class="xref py py-func docutils literal"><span class="pre">shelve.open()</span></code></a>作为上下文管理器:</span></p><div class="last highlight-python3"><div class="highlight"><pre><span></span><span class="k">with</span> <span class="n">shelve</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">'spam'</span><span class="p">)</span> <span class="k">as</span> <span class="n">db</span><span class="p">:</span>
|
||
<span class="n">db</span><span class="p">[</span><span class="s1">'eggs'</span><span class="p">]</span> <span class="o">=</span> <span class="s1">'eggs'</span>
|
||
</pre></div></div></div></dd></dl><div class="admonition warning"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-30">警告</span></p><p class="last"><span class="yiyi-st" id="yiyi-31">由于<a class="reference internal" href="#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal"><span class="pre">shelve</span></code></a>模块由<a class="reference internal" href="pickle.html#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal"><span class="pre">pickle</span></code></a>支持,因此从不受信任的来源加载搁架是不安全的。</span><span class="yiyi-st" id="yiyi-32">像pickle一样,加载货架可以执行任意代码。</span></p></div><p><span class="yiyi-st" id="yiyi-33">Shelf对象支持字典支持的所有方法。</span><span class="yiyi-st" id="yiyi-34">这简化了从基于字典的脚本到需要持久存储的脚本的过渡。</span></p><p><span class="yiyi-st" id="yiyi-35">支持两种其他方法:</span></p><dl class="method"><dt id="shelve.Shelf.sync"><span class="yiyi-st" id="yiyi-36"> <code class="descclassname">Shelf.</code><code class="descname">sync</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-37">如果以<em>writeback</em>设置为<a class="reference internal" href="constants.html#True" title="True"><code class="xref py py-const docutils literal"><span class="pre">True</span></code></a>打开机架,则写回缓存中的所有条目。</span><span class="yiyi-st" id="yiyi-38">同时清空缓存并同步磁盘上的持久性字典(如果可行)。</span><span class="yiyi-st" id="yiyi-39">当搁架用<a class="reference internal" href="#shelve.Shelf.close" title="shelve.Shelf.close"><code class="xref py py-meth docutils literal"><span class="pre">close()</span></code></a>关闭时会自动调用。</span></p></dd></dl><dl class="method"><dt id="shelve.Shelf.close"><span class="yiyi-st" id="yiyi-40"> <code class="descclassname">Shelf.</code><code class="descname">close</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-41">同步并关闭持久性<em>dict</em>对象。</span><span class="yiyi-st" id="yiyi-42">封闭货架上的操作将失败,并显示<a class="reference internal" href="exceptions.html#ValueError" title="ValueError"><code class="xref py py-exc docutils literal"><span class="pre">ValueError</span></code></a>。</span></p></dd></dl><div class="admonition seealso"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-43">也可以看看</span></p><p class="last"><span class="yiyi-st" id="yiyi-44"><a class="reference external" href="https://code.activestate.com/recipes/576642/">持久性字典配方</a>具有广泛支持的存储格式并具有本地字典的速度。</span></p></div><div class="section" id="restrictions"><h2><span class="yiyi-st" id="yiyi-45">12.3.1. </span><span class="yiyi-st" id="yiyi-46">Restrictions</span></h2><ul class="simple" id="index-1"><li><span class="yiyi-st" id="yiyi-47">将选择使用哪个数据库包(例如<a class="reference internal" href="dbm.html#module-dbm.ndbm" title='dbm.ndbm: The standard "database" interface, based on ndbm. (Unix)'><code class="xref py py-mod docutils literal"><span class="pre">dbm.ndbm</span></code></a>或<a class="reference internal" href="dbm.html#module-dbm.gnu" title="dbm.gnu: GNU's reinterpretation of dbm. (Unix)"><code class="xref py py-mod docutils literal"><span class="pre">dbm.gnu</span></code></a>)取决于哪个接口可用。</span><span class="yiyi-st" id="yiyi-48">因此,使用<a class="reference internal" href="dbm.html#module-dbm" title='dbm: Interfaces to various Unix "database" formats.'><code class="xref py py-mod docutils literal"><span class="pre">dbm</span></code></a>直接打开数据库是不安全的。</span><span class="yiyi-st" id="yiyi-49">数据库也是(不幸的是)受到<a class="reference internal" href="dbm.html#module-dbm" title='dbm: Interfaces to various Unix "database" formats.'><code class="xref py py-mod docutils literal"><span class="pre">dbm</span></code></a>的限制,如果它被使用 - 这意味着存储在数据库中的对象(的腌制表示)应当相当小,在极少数情况下键冲突可能导致数据库拒绝更新。</span></li><li><span class="yiyi-st" id="yiyi-50"><a class="reference internal" href="#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal"><span class="pre">shelve</span></code></a>模块不支持<em>并发</em>对搁置对象的读/写访问。</span><span class="yiyi-st" id="yiyi-51">(多个同时读取访问是安全的。)</span><span class="yiyi-st" id="yiyi-52">当一个程序有一个开放的书架,没有其他程序应该打开读或写。</span><span class="yiyi-st" id="yiyi-53">Unix文件锁定可以用来解决这个问题,但这在Unix版本中有所不同,需要了解所使用的数据库实现。</span></li></ul><dl class="class"><dt id="shelve.Shelf"><span class="yiyi-st" id="yiyi-54"> <em class="property">class </em><code class="descclassname">shelve.</code><code class="descname">Shelf</code><span class="sig-paren">(</span><em>dict</em>, <em>protocol=None</em>, <em>writeback=False</em>, <em>keyencoding='utf-8'</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-55"><a class="reference internal" href="collections.abc.html#collections.abc.MutableMapping" title="collections.abc.MutableMapping"><code class="xref py py-class docutils literal"><span class="pre">collections.abc.MutableMapping</span></code></a>的子类,用于在<em>dict</em>对象中存储pickled值。</span></p><p><span class="yiyi-st" id="yiyi-56">默认情况下,版本3pickles用于序列化值。</span><span class="yiyi-st" id="yiyi-57">可以使用<em>协议</em>参数指定pickle协议的版本。</span><span class="yiyi-st" id="yiyi-58">有关pickle协议的讨论,请参阅<a class="reference internal" href="pickle.html#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal"><span class="pre">pickle</span></code></a>文档。</span></p><p><span class="yiyi-st" id="yiyi-59">如果<em>writeback</em>参数为<code class="docutils literal"><span class="pre">True</span></code>,则对象将保存所有访问的缓存,并在同步和关闭时间将它们写回<em>dict</em> 。</span><span class="yiyi-st" id="yiyi-60">这允许对可变条目的自然操作,但可以消耗更多的内存,并使同步和关闭需要很长时间。</span></p><p><span class="yiyi-st" id="yiyi-61"><em>keyencoding</em>参数是用于在键与底层dict一起使用之前对其进行编码的编码。</span></p><p><span class="yiyi-st" id="yiyi-62"><a class="reference internal" href="#shelve.Shelf" title="shelve.Shelf"><code class="xref py py-class docutils literal"><span class="pre">Shelf</span></code></a>对象也可以用作上下文管理器,在<a class="reference internal" href="../reference/compound_stmts.html#with"><code class="xref std std-keyword docutils literal"><span class="pre">with</span></code></a>块结束时,它将自动关闭。</span></p><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-63"><span class="versionmodified">在版本3.2中更改:</span>添加了<em>keyencoding</em>参数;以前,密钥始终以UTF-8编码。</span></p></div><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-64"><span class="versionmodified">在版本3.4中更改:</span>添加了上下文管理器支持。</span></p></div></dd></dl><dl class="class"><dt id="shelve.BsdDbShelf"><span class="yiyi-st" id="yiyi-65"> <em class="property">class </em><code class="descclassname">shelve.</code><code class="descname">BsdDbShelf</code><span class="sig-paren">(</span><em>dict</em>, <em>protocol=None</em>, <em>writeback=False</em>, <em>keyencoding='utf-8'</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-66">A subclass of <a class="reference internal" href="#shelve.Shelf" title="shelve.Shelf"><code class="xref py py-class docutils literal"><span class="pre">Shelf</span></code></a> which exposes <code class="xref py py-meth docutils literal"><span class="pre">first()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">next()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">previous()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">last()</span></code> and <code class="xref py py-meth docutils literal"><span class="pre">set_location()</span></code> which are available in the third-party <code class="xref py py-mod docutils literal"><span class="pre">bsddb</span></code> module from <a class="reference external" href="https://www.jcea.es/programacion/pybsddb.htm">pybsddb</a> but not in other database modules. </span><span class="yiyi-st" id="yiyi-67">传递给构造函数的<em>dict</em>对象必须支持这些方法。</span><span class="yiyi-st" id="yiyi-68">这通常通过调用<code class="xref py py-func docutils literal"><span class="pre">bsddb.hashopen()</span></code>,<code class="xref py py-func docutils literal"><span class="pre">bsddb.btopen()</span></code>或<code class="xref py py-func docutils literal"><span class="pre">bsddb.rnopen()</span></code>之一来完成。</span><span class="yiyi-st" id="yiyi-69">可选的<em>协议</em>,<em>回写</em>和<em>keyencoding</em>参数具有与<a class="reference internal" href="#shelve.Shelf" title="shelve.Shelf"><code class="xref py py-class docutils literal"><span class="pre">Shelf</span></code></a>类相同的解释。</span></p></dd></dl><dl class="class"><dt id="shelve.DbfilenameShelf"><span class="yiyi-st" id="yiyi-70"> <em class="property">class </em><code class="descclassname">shelve.</code><code class="descname">DbfilenameShelf</code><span class="sig-paren">(</span><em>filename</em>, <em>flag='c'</em>, <em>protocol=None</em>, <em>writeback=False</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-71"><a class="reference internal" href="#shelve.Shelf" title="shelve.Shelf"><code class="xref py py-class docutils literal"><span class="pre">Shelf</span></code></a>的子类,它接受<em>文件名</em>而不是类似dict的对象。</span><span class="yiyi-st" id="yiyi-72">底层文件将使用<a class="reference internal" href="dbm.html#dbm.open" title="dbm.open"><code class="xref py py-func docutils literal"><span class="pre">dbm.open()</span></code></a>打开。</span><span class="yiyi-st" id="yiyi-73">默认情况下,将创建并打开文件以进行读取和写入。</span><span class="yiyi-st" id="yiyi-74">可选的<em>标志</em>参数与<a class="reference internal" href="#shelve.open" title="shelve.open"><code class="xref py py-func docutils literal"><span class="pre">open()</span></code></a>函数具有相同的解释。</span><span class="yiyi-st" id="yiyi-75">可选的<em>协议</em>和<em>回写</em>参数具有与<a class="reference internal" href="#shelve.Shelf" title="shelve.Shelf"><code class="xref py py-class docutils literal"><span class="pre">Shelf</span></code></a>类相同的解释。</span></p></dd></dl></div><div class="section" id="example"><h2><span class="yiyi-st" id="yiyi-76">12.3.2. </span><span class="yiyi-st" id="yiyi-77">Example</span></h2><p><span class="yiyi-st" id="yiyi-78">要总结接口(<code class="docutils literal"><span class="pre">key</span></code>是一个字符串,<code class="docutils literal"><span class="pre">data</span></code>是一个任意对象):</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">shelve</span>
|
||
|
||
<span class="n">d</span> <span class="o">=</span> <span class="n">shelve</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="c1"># open -- file may get suffix added by low-level</span>
|
||
<span class="c1"># library</span>
|
||
|
||
<span class="n">d</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span> <span class="c1"># store data at key (overwrites old data if</span>
|
||
<span class="c1"># using an existing key)</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="n">d</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="c1"># retrieve a COPY of data at key (raise KeyError</span>
|
||
<span class="c1"># if no such key)</span>
|
||
<span class="k">del</span> <span class="n">d</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="c1"># delete data stored at key (raises KeyError</span>
|
||
<span class="c1"># if no such key)</span>
|
||
|
||
<span class="n">flag</span> <span class="o">=</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">d</span> <span class="c1"># true if the key exists</span>
|
||
<span class="n">klist</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">d</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span> <span class="c1"># a list of all existing keys (slow!)</span>
|
||
|
||
<span class="c1"># as d was opened WITHOUT writeback=True, beware:</span>
|
||
<span class="n">d</span><span class="p">[</span><span class="s1">'xx'</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="c1"># this works as expected, but...</span>
|
||
<span class="n">d</span><span class="p">[</span><span class="s1">'xx'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="c1"># *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!</span>
|
||
|
||
<span class="c1"># having opened d without writeback=True, you need to code carefully:</span>
|
||
<span class="n">temp</span> <span class="o">=</span> <span class="n">d</span><span class="p">[</span><span class="s1">'xx'</span><span class="p">]</span> <span class="c1"># extracts the copy</span>
|
||
<span class="n">temp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="c1"># mutates the copy</span>
|
||
<span class="n">d</span><span class="p">[</span><span class="s1">'xx'</span><span class="p">]</span> <span class="o">=</span> <span class="n">temp</span> <span class="c1"># stores the copy right back, to persist it</span>
|
||
|
||
<span class="c1"># or, d=shelve.open(filename,writeback=True) would let you just code</span>
|
||
<span class="c1"># d['xx'].append(5) and have it work as expected, BUT it would also</span>
|
||
<span class="c1"># consume more memory and make the d.close() operation slower.</span>
|
||
|
||
<span class="n">d</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="c1"># close it</span>
|
||
</code></pre><div class="admonition seealso"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-79">也可以看看</span></p><dl class="last docutils"><dt><span class="yiyi-st" id="yiyi-80">模块<a class="reference internal" href="dbm.html#module-dbm" title='dbm: Interfaces to various Unix "database" formats.'><code class="xref py py-mod docutils literal"><span class="pre">dbm</span></code></a></span></dt><dd><span class="yiyi-st" id="yiyi-81"><code class="docutils literal"><span class="pre">dbm</span></code>样式数据库的通用接口。</span></dd><dt><span class="yiyi-st" id="yiyi-82">模块<a class="reference internal" href="pickle.html#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal"><span class="pre">pickle</span></code></a></span></dt><dd><span class="yiyi-st" id="yiyi-83"><a class="reference internal" href="#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal"><span class="pre">shelve</span></code></a>使用的对象序列化。</span></dd></dl></div></div></div></div> |