mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-08 23:14:06 +08:00
214 lines
105 KiB
HTML
214 lines
105 KiB
HTML
<div class="body" role="main"><div class="section" id="module-pickle"><h1><span class="yiyi-st" id="yiyi-10">12.1. <a class="reference internal" href="#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> - 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/pickle.py">Lib / pickle.py</a></span></p><p><span class="yiyi-st" id="yiyi-12"><a class="reference internal" href="#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>模块实现了用于对Python对象结构进行序列化和反序列化的二进制协议。</span><span class="yiyi-st" id="yiyi-13"><em>“Pickling”</em>是将Python对象转换为字节流的过程,<em>“unpickling”</em>是反向操作,由此字节流<a class="reference internal" href="../glossary.html#term-binary-file"><span class="xref std std-term">二进制文件</span></a>或<a class="reference internal" href="../glossary.html#term-bytes-like-object"><span class="xref std std-term">字节对象</span></a>)转换回对象结构。</span><span class="yiyi-st" id="yiyi-14">酸洗(和解胶)也称为“串联”,“编组”,<a class="footnote-reference" href="#id6" id="id1">[1]</a>或“压平”;然而,为了避免混淆,这里使用的术语是“pickling”和“unpickling”。</span></p><div class="admonition warning"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-15">警告</span></p><p class="last"><span class="yiyi-st" id="yiyi-16"><a class="reference internal" href="#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-17">切勿从不受信任或未经身份验证的来源接收数据。</span></p></div><div class="section" id="relationship-to-other-python-modules"><h2><span class="yiyi-st" id="yiyi-18">12.1.1</span><span class="yiyi-st" id="yiyi-19">与其他Python模块的关系</span></h2><div class="section" id="comparison-with-marshal"><h3><span class="yiyi-st" id="yiyi-20">12.1.1.1.</span><span class="yiyi-st" id="yiyi-21">与<code class="docutils literal"><span class="pre">marshal</span></code>的比较</span></h3><p><span class="yiyi-st" id="yiyi-22">Python有一个更原始的序列化模块,称为<a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a>,但是一般情况下<a class="reference internal" href="#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>应该始终是序列化Python对象的首选方法。</span><span class="yiyi-st" id="yiyi-23"><a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a>主要用于支持Python的<code class="file docutils literal"><span class="pre">.pyc</span></code>文件。</span></p><p><span class="yiyi-st" id="yiyi-24"><a class="reference internal" href="#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>模块有以下几个重要方面不同于<a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a>:</span></p><ul><li><p class="first"><span class="yiyi-st" id="yiyi-25"><a class="reference internal" href="#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-26"><a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a>则不会这样做。</span></p><p><span class="yiyi-st" id="yiyi-27">这对于递归对象和对象共享都有影响。</span><span class="yiyi-st" id="yiyi-28">递归对象是包含对自身的引用的对象。</span><span class="yiyi-st" id="yiyi-29">这些不是元组处理,事实上,尝试封送递归对象会导致Python解释器崩溃。</span><span class="yiyi-st" id="yiyi-30">当在对象层次结构中的不同位置对同一对象进行多个引用被序列化时,将发生对象共享。</span><span class="yiyi-st" id="yiyi-31"><a class="reference internal" href="#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">共享对象保持共享,这对可变对象非常重要。</span></p></li><li><p class="first"><span class="yiyi-st" id="yiyi-33"><a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a>不能用于序列化用户定义的类及其实例。</span><span class="yiyi-st" id="yiyi-34"><a class="reference internal" href="#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></li><li><p class="first"><span class="yiyi-st" id="yiyi-35"><a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a>序列化格式不能保证在Python版本之间可移植。</span><span class="yiyi-st" id="yiyi-36">由于其生命中的主要工作是支持<code class="file docutils literal"><span class="pre">.pyc</span></code>文件,Python实现者保留在需要时以非向后兼容的方式更改序列化格式的权利。</span><span class="yiyi-st" id="yiyi-37"><a class="reference internal" href="#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>序列化格式保证在Python版本之间向后兼容。</span></p></li></ul></div><div class="section" id="comparison-with-json"><h3><span class="yiyi-st" id="yiyi-38">12.1.1.2.</span><span class="yiyi-st" id="yiyi-39">与<code class="docutils literal"><span class="pre">json</span></code>的比较</span></h3><p><span class="yiyi-st" id="yiyi-40">在pickle协议和<a class="reference external" href="http://json.org">JSON(JavaScript对象表示法)</a>之间存在根本区别:</span></p><ul class="simple"><li><span class="yiyi-st" id="yiyi-41">JSON是一种文本序列化格式(它输出unicode文本,虽然大多数时候它被编码为<code class="docutils literal"><span class="pre">utf-8</span></code>),而pickle是一个二进制序列化格式;</span></li><li><span class="yiyi-st" id="yiyi-42">JSON是人类可读的,而pickle不是;</span></li><li><span class="yiyi-st" id="yiyi-43">JSON是可互操作的,并且在Python生态系统之外广泛使用,而pickle是特定于Python的;</span></li><li><span class="yiyi-st" id="yiyi-44">默认情况下,JSON只能表示Python内建类型的一个子集,并且没有自定义类; pickle可以代表极大数量的Python类型(其中许多是通过巧妙地使用Python内省功能自动实现的;复杂的情况可以通过实现<a class="reference internal" href="#pickle-inst"><span>specific object APIs</span></a>来解决)。</span></li></ul><div class="admonition seealso"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-45">也可以看看</span></p><p class="last"><span class="yiyi-st" id="yiyi-46"><a class="reference internal" href="json.html#module-json" title="json: Encode and decode the JSON format."><code class="xref py py-mod docutils literal"><span class="pre">json</span></code></a>模块:允许JSON序列化和反序列化的标准库模块。</span></p></div></div></div><div class="section" id="data-stream-format"><h2><span class="yiyi-st" id="yiyi-47">12.1.2.</span><span class="yiyi-st" id="yiyi-48">数据流格式</span></h2><p id="index-1"><span class="yiyi-st" id="yiyi-49"><a class="reference internal" href="#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>使用的数据格式是特定于Python的。</span><span class="yiyi-st" id="yiyi-50">这具有的优点是没有由诸如JSON或XDR(其不能表示指针共享)的外部标准强加的限制;然而这意味着非Python程序可能无法重建pickled Python对象。</span></p><p><span class="yiyi-st" id="yiyi-51">默认情况下,<a class="reference internal" href="#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-52">如果您需要最佳大小特征,则可以有效地<a class="reference internal" href="archiving.html"><em>compress</em></a> pickled数据。</span></p><p><span class="yiyi-st" id="yiyi-53">模块<a class="reference internal" href="pickletools.html#module-pickletools" title="pickletools: Contains extensive comments about the pickle protocols and pickle-machine opcodes, as well as some useful functions."><code class="xref py py-mod docutils literal"><span class="pre">pickletools</span></code></a>包含用于分析<a class="reference internal" href="#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-54"><a class="reference internal" href="pickletools.html#module-pickletools" title="pickletools: Contains extensive comments about the pickle protocols and pickle-machine opcodes, as well as some useful functions."><code class="xref py py-mod docutils literal"><span class="pre">pickletools</span></code></a>源代码对pickle协议使用的操作码有广泛的意见。</span></p><p><span class="yiyi-st" id="yiyi-55">目前有5种不同的协议可以用于pickling。</span><span class="yiyi-st" id="yiyi-56">使用的协议越高,更新的Python版本需要读取生产的pickle。</span></p><ul class="simple"><li><span class="yiyi-st" id="yiyi-57">协议版本0是原始的“人类可读”协议,并且向后兼容早期版本的Python。</span></li><li><span class="yiyi-st" id="yiyi-58">协议版本1是一个旧的二进制格式,也与早期版本的Python兼容。</span></li><li><span class="yiyi-st" id="yiyi-59">协议版本2在Python 2.3中引入。</span><span class="yiyi-st" id="yiyi-60">它提供<a class="reference internal" href="../glossary.html#term-new-style-class"><span class="xref std std-term">new-style class</span></a>更高效的酸洗。</span><span class="yiyi-st" id="yiyi-61">有关协议2带来的改进的信息,请参阅<span class="target" id="index-2"></span> <a class="pep reference external" href="https://www.python.org/dev/peps/pep-0307"><strong>PEP 307</strong></a>。</span></li><li><span class="yiyi-st" id="yiyi-62">在Python 3.0中添加了协议版本3。</span><span class="yiyi-st" id="yiyi-63">它明确支持<a class="reference internal" href="functions.html#bytes" title="bytes"><code class="xref py py-class docutils literal"><span class="pre">bytes</span></code></a>对象,不能由Python 2.x取消绑定。</span><span class="yiyi-st" id="yiyi-64">这是默认协议,当与其他Python 3版本兼容时需要推荐的协议。</span></li><li><span class="yiyi-st" id="yiyi-65">在Python 3.4中添加了协议版本4。</span><span class="yiyi-st" id="yiyi-66">它增加了对非常大的对象,pickling更多种类的对象和一些数据格式优化的支持。</span><span class="yiyi-st" id="yiyi-67">有关协议4带来的改进的信息,请参见<span class="target" id="index-3"></span> <a class="pep reference external" href="https://www.python.org/dev/peps/pep-3154"><strong>PEP 3154</strong></a>。</span></li></ul><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-68">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-69">序列化是比持久化更原始的概念;虽然<a class="reference internal" href="#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-70"><a class="reference internal" href="#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-71">也许与这些字节流最明显的事情是将它们写入文件,但也可以通过网络发送它们或将它们存储在数据库中。</span><span class="yiyi-st" id="yiyi-72"><a class="reference internal" href="shelve.html#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal"><span class="pre">shelve</span></code></a>模块提供了一个简单的界面,用于在DBM风格的数据库文件上对对象进行pickle和unpickle。</span></p></div></div><div class="section" id="module-interface"><h2><span class="yiyi-st" id="yiyi-73">12.1.3.</span><span class="yiyi-st" id="yiyi-74">模块接口</span></h2><p><span class="yiyi-st" id="yiyi-75">要序列化对象层次结构,只需调用<a class="reference internal" href="#pickle.dumps" title="pickle.dumps"><code class="xref py py-func docutils literal"><span class="pre">dumps()</span></code></a>函数。</span><span class="yiyi-st" id="yiyi-76">类似地,要解串行化数据流,您可以调用<a class="reference internal" href="#pickle.loads" title="pickle.loads"><code class="xref py py-func docutils literal"><span class="pre">loads()</span></code></a>函数。</span><span class="yiyi-st" id="yiyi-77">但是,如果您想要更多地控制序列化和反序列化,您可以分别创建<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">Pickler</span></code></a>或<a class="reference internal" href="#pickle.Unpickler" title="pickle.Unpickler"><code class="xref py py-class docutils literal"><span class="pre">Unpickler</span></code></a>对象。</span></p><p><span class="yiyi-st" id="yiyi-78"><a class="reference internal" href="#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><dl class="data"><dt id="pickle.HIGHEST_PROTOCOL"><span class="yiyi-st" id="yiyi-79"> <code class="descclassname">pickle.</code><code class="descname">HIGHEST_PROTOCOL</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-80">整数,最高的<a class="reference internal" href="#pickle-protocols"><span>protocol version</span></a>可用。</span><span class="yiyi-st" id="yiyi-81">此值可作为<em>协议</em>值传递给函数<a class="reference internal" href="#pickle.dump" title="pickle.dump"><code class="xref py py-func docutils literal"><span class="pre">dump()</span></code></a>和<a class="reference internal" href="#pickle.dumps" title="pickle.dumps"><code class="xref py py-func docutils literal"><span class="pre">dumps()</span></code></a>以及<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">Pickler</span></code></a></span></p></dd></dl><dl class="data"><dt id="pickle.DEFAULT_PROTOCOL"><span class="yiyi-st" id="yiyi-82"> <code class="descclassname">pickle.</code><code class="descname">DEFAULT_PROTOCOL</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-83">整数,默认的<a class="reference internal" href="#pickle-protocols"><span>protocol version</span></a>用于酸洗。</span><span class="yiyi-st" id="yiyi-84">可能小于<a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。</span><span class="yiyi-st" id="yiyi-85">目前默认的协议是3,一个为Python 3设计的新协议。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-86"><a class="reference internal" href="#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><dl class="function"><dt id="pickle.dump"><span class="yiyi-st" id="yiyi-87"> <code class="descclassname">pickle.</code><code class="descname">dump</code><span class="sig-paren">(</span><em>obj</em>, <em>file</em>, <em>protocol=None</em>, <em>*</em>, <em>fix_imports=True</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-88">将<em>obj</em>的腌制表示写入打开的<a class="reference internal" href="../glossary.html#term-file-object"><span class="xref std std-term">file object</span></a> <em>文件</em>。</span><span class="yiyi-st" id="yiyi-89">这相当于<code class="docutils literal"><span class="pre">Pickler(文件,</span> <span class="pre">协议).dump(obj)</span></code>。</span></p><p><span class="yiyi-st" id="yiyi-90">可选的<em>协议</em>参数,一个整数,告诉pickler使用给定的协议;支持的协议为0到<a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。</span><span class="yiyi-st" id="yiyi-91">如果未指定,默认值为<a class="reference internal" href="#pickle.DEFAULT_PROTOCOL" title="pickle.DEFAULT_PROTOCOL"><code class="xref py py-data docutils literal"><span class="pre">DEFAULT_PROTOCOL</span></code></a>。</span><span class="yiyi-st" id="yiyi-92">如果指定了负数,则选择<a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-93"><em>文件</em>参数必须具有接受单个字节参数的write()方法。</span><span class="yiyi-st" id="yiyi-94">因此,它可以是为二进制写入打开的磁盘文件,<a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal"><span class="pre">io.BytesIO</span></code></a>实例或满足此接口的任何其他自定义对象。</span></p><p><span class="yiyi-st" id="yiyi-95">如果<em>fix_imports</em>为true且<em>protocol</em>小于3,pickle将尝试将新的Python 3名称映射到Python 2中使用的旧模块名称,以便pickle数据流可以用Python 2读取。</span></p></dd></dl><dl class="function"><dt id="pickle.dumps"><span class="yiyi-st" id="yiyi-96"> <code class="descclassname">pickle.</code><code class="descname">dumps</code><span class="sig-paren">(</span><em>obj</em>, <em>protocol=None</em>, <em>*</em>, <em>fix_imports=True</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-97">将对象的腌制表示作为<a class="reference internal" href="functions.html#bytes" title="bytes"><code class="xref py py-class docutils literal"><span class="pre">bytes</span></code></a>对象返回,而不是将其写入文件。</span></p><p><span class="yiyi-st" id="yiyi-98">参数<em>protocol</em>和<em>fix_imports</em>的含义与<a class="reference internal" href="#pickle.dump" title="pickle.dump"><code class="xref py py-func docutils literal"><span class="pre">dump()</span></code></a>中的含义相同。</span></p></dd></dl><dl class="function"><dt id="pickle.load"><span class="yiyi-st" id="yiyi-99"> <code class="descclassname">pickle.</code><code class="descname">load</code><span class="sig-paren">(</span><em>file</em>, <em>*</em>, <em>fix_imports=True</em>, <em>encoding="ASCII"</em>, <em>errors="strict"</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-100">从打开的<a class="reference internal" href="../glossary.html#term-file-object"><span class="xref std std-term">文件对象</span></a><em>file</em>读取pickled对象表示形式,并返回其中重新构建的对象层次结构。</span><span class="yiyi-st" id="yiyi-101">它等同于<code class="docutils literal"><span class="pre">Unpickler(file).load()</span></code>。</span></p><p><span class="yiyi-st" id="yiyi-102">Pickle协议的版本会自动检测,所以不需要protocol参数。</span><span class="yiyi-st" id="yiyi-103">超过腌制对象表示的字节将被忽略。</span></p><p><span class="yiyi-st" id="yiyi-104">参数<em>文件</em>必须有两个方法,一个读取整数参数的read()方法和一个不需要参数的readline()方法。</span><span class="yiyi-st" id="yiyi-105">这两种方法都应该返回字节。</span><span class="yiyi-st" id="yiyi-106">因此,<em>文件</em>可以是为二进制读取打开的磁盘文件,<a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal"><span class="pre">io.BytesIO</span></code></a>对象或满足此接口的任何其他自定义对象。</span></p><p><span class="yiyi-st" id="yiyi-107">可选的关键字参数是<em>fix_imports</em>,<em>编码</em>和<em>错误</em>,用于控制Python 2生成的pickle流的兼容性支持。</span><span class="yiyi-st" id="yiyi-108">如果<em>fix_imports</em>为true,pickle将尝试将旧的Python 2名称映射到Python 3中使用的新名称。</span><span class="yiyi-st" id="yiyi-109"><em>编码</em>和<em>错误</em>告诉pickle如何解码由Python 2 pickled的8位字符串实例;这些默认分别为'ASCII'和'strict'。</span><span class="yiyi-st" id="yiyi-110"><em>编码</em>可以是“bytes”来读取这些8位字符串实例作为字节对象。</span></p></dd></dl><dl class="function"><dt id="pickle.loads"><span class="yiyi-st" id="yiyi-111"> <code class="descclassname">pickle.</code><code class="descname">loads</code><span class="sig-paren">(</span><em>bytes_object</em>, <em>*</em>, <em>fix_imports=True</em>, <em>encoding="ASCII"</em>, <em>errors="strict"</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-112">从<a class="reference internal" href="functions.html#bytes" title="bytes"><code class="xref py py-class docutils literal"><span class="pre">bytes</span></code></a>对象读取腌制对象层次结构,并返回其中指定的重构对象层次结构。</span></p><p><span class="yiyi-st" id="yiyi-113">腌汁的协议版本被自动检测,因此不需要协议参数。</span><span class="yiyi-st" id="yiyi-114">超过腌制对象表示的字节将被忽略。</span></p><p><span class="yiyi-st" id="yiyi-115">可选的关键字参数是<em>fix_imports</em>,<em>编码</em>和<em>错误</em>,用于控制Python 2生成的pickle流的兼容性支持。</span><span class="yiyi-st" id="yiyi-116">如果<em>fix_imports</em>为true,pickle将尝试将旧的Python 2名称映射到Python 3中使用的新名称。</span><span class="yiyi-st" id="yiyi-117"><em>编码</em>和<em>错误</em>告诉pickle如何解码由Python 2 pickled的8位字符串实例;这些默认分别为'ASCII'和'strict'。</span><span class="yiyi-st" id="yiyi-118"><em>编码</em>可以是“bytes”来读取这些8位字符串实例作为字节对象。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-119"><a class="reference internal" href="#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><dl class="exception"><dt id="pickle.PickleError"><span class="yiyi-st" id="yiyi-120"> <em class="property">exception </em><code class="descclassname">pickle.</code><code class="descname">PickleError</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-121">其他pickling异常的公共基类。</span><span class="yiyi-st" id="yiyi-122">它继承<a class="reference internal" href="exceptions.html#Exception" title="Exception"><code class="xref py py-exc docutils literal"><span class="pre">Exception</span></code></a>。</span></p></dd></dl><dl class="exception"><dt id="pickle.PicklingError"><span class="yiyi-st" id="yiyi-123"> <em class="property">exception </em><code class="descclassname">pickle.</code><code class="descname">PicklingError</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-124"><a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">Pickler</span></code></a>遇到不可拆分对象时引发错误。</span><span class="yiyi-st" id="yiyi-125">它继承<a class="reference internal" href="#pickle.PickleError" title="pickle.PickleError"><code class="xref py py-exc docutils literal"><span class="pre">PickleError</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-126">请参阅<a class="reference internal" href="#pickle-picklable"><span>What can be pickled and unpickled?</span></a></span><span class="yiyi-st" id="yiyi-127">以了解什么类型的对象可以腌制。</span></p></dd></dl><dl class="exception"><dt id="pickle.UnpicklingError"><span class="yiyi-st" id="yiyi-128"> <em class="property">exception </em><code class="descclassname">pickle.</code><code class="descname">UnpicklingError</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-129">在解除对象的取消(例如数据损坏或安全违规)时出现问题。</span><span class="yiyi-st" id="yiyi-130">它继承<a class="reference internal" href="#pickle.PickleError" title="pickle.PickleError"><code class="xref py py-exc docutils literal"><span class="pre">PickleError</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-131">注意,在解压缩期间也可以引发其他异常,包括(但不一定限于)AttributeError,EOFError,ImportError和IndexError。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-132"><a class="reference internal" href="#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>模块导出两个类,<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">Pickler</span></code></a>和<a class="reference internal" href="#pickle.Unpickler" title="pickle.Unpickler"><code class="xref py py-class docutils literal"><span class="pre">Unpickler</span></code></a>:</span></p><dl class="class"><dt id="pickle.Pickler"><span class="yiyi-st" id="yiyi-133"> <em class="property">class </em><code class="descclassname">pickle.</code><code class="descname">Pickler</code><span class="sig-paren">(</span><em>file</em>, <em>protocol=None</em>, <em>*</em>, <em>fix_imports=True</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-134">这需要一个二进制文件来写一个pickle数据流。</span></p><p><span class="yiyi-st" id="yiyi-135">可选的<em>协议</em>参数,一个整数,告诉pickler使用给定的协议;支持的协议为0到<a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。</span><span class="yiyi-st" id="yiyi-136">如果未指定,默认值为<a class="reference internal" href="#pickle.DEFAULT_PROTOCOL" title="pickle.DEFAULT_PROTOCOL"><code class="xref py py-data docutils literal"><span class="pre">DEFAULT_PROTOCOL</span></code></a>。</span><span class="yiyi-st" id="yiyi-137">如果指定了负数,则选择<a class="reference internal" href="#pickle.HIGHEST_PROTOCOL" title="pickle.HIGHEST_PROTOCOL"><code class="xref py py-data docutils literal"><span class="pre">HIGHEST_PROTOCOL</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-138"><em>文件</em>参数必须具有接受单个字节参数的write()方法。</span><span class="yiyi-st" id="yiyi-139">因此,它可以是为二进制写入打开的磁盘文件,<a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal"><span class="pre">io.BytesIO</span></code></a>实例或满足此接口的任何其他自定义对象。</span></p><p><span class="yiyi-st" id="yiyi-140">如果<em>fix_imports</em>为true且<em>protocol</em>小于3,pickle将尝试将新的Python 3名称映射到Python 2中使用的旧模块名称,以便pickle数据流可以用Python 2读取。</span></p><dl class="method"><dt id="pickle.Pickler.dump"><span class="yiyi-st" id="yiyi-141"> <code class="descname">dump</code><span class="sig-paren">(</span><em>obj</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-142">将<em>obj</em>的腌制表示写入构造函数中给出的打开文件对象。</span></p></dd></dl><dl class="method"><dt id="pickle.Pickler.persistent_id"><span class="yiyi-st" id="yiyi-143"> <code class="descname">persistent_id</code><span class="sig-paren">(</span><em>obj</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-144">默认情况下不执行任何操作。</span><span class="yiyi-st" id="yiyi-145">这存在,所以一个子类可以覆盖它。</span></p><p><span class="yiyi-st" id="yiyi-146">如果<a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal"><span class="pre">persistent_id()</span></code></a>返回<code class="docutils literal"><span class="pre">None</span></code>,<em>obj</em>像往常一样被选中。</span><span class="yiyi-st" id="yiyi-147">任何其他值会导致<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">Pickler</span></code></a>将返回的值作为<em>obj</em>的持久性标识发出。</span><span class="yiyi-st" id="yiyi-148">此持久性ID的含义应由<a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal"><span class="pre">Unpickler.persistent_load()</span></code></a>定义。</span><span class="yiyi-st" id="yiyi-149">请注意,<a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal"><span class="pre">persistent_id()</span></code></a>返回的值本身不能有持久性ID。</span></p><p><span class="yiyi-st" id="yiyi-150">有关使用的详细信息和示例,请参见<a class="reference internal" href="#pickle-persistent"><span>Persistence of External Objects</span></a>。</span></p></dd></dl><dl class="attribute"><dt id="pickle.Pickler.dispatch_table"><span class="yiyi-st" id="yiyi-151"> <code class="descname">dispatch_table</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-152">pickler对象的调度表是可以使用<a class="reference internal" href="copyreg.html#copyreg.pickle" title="copyreg.pickle"><code class="xref py py-func docutils literal"><span class="pre">copyreg.pickle()</span></code></a>声明的<em>缩减函数</em>的注册表。</span><span class="yiyi-st" id="yiyi-153">它是一个映射,其键是类并且其值是缩减函数。</span><span class="yiyi-st" id="yiyi-154">减少函数接受关联类的单个参数,并且应该符合与<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce__()</span></code></a>方法相同的接口。</span></p><p><span class="yiyi-st" id="yiyi-155">By default, a pickler object will not have a <a class="reference internal" href="#pickle.Pickler.dispatch_table" title="pickle.Pickler.dispatch_table"><code class="xref py py-attr docutils literal"><span class="pre">dispatch_table</span></code></a> attribute, and it will instead use the global dispatch table managed by the <a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal"><span class="pre">copyreg</span></code></a> module. </span><span class="yiyi-st" id="yiyi-156">但是,要自定义特定pickler对象的pickling,可以将<a class="reference internal" href="#pickle.Pickler.dispatch_table" title="pickle.Pickler.dispatch_table"><code class="xref py py-attr docutils literal"><span class="pre">dispatch_table</span></code></a>属性设置为类似dict的对象。</span><span class="yiyi-st" id="yiyi-157">或者,如果<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">Pickler</span></code></a>的子类具有<a class="reference internal" href="#pickle.Pickler.dispatch_table" title="pickle.Pickler.dispatch_table"><code class="xref py py-attr docutils literal"><span class="pre">dispatch_table</span></code></a>属性,那么这将用作该类的实例的默认分派表。</span></p><p><span class="yiyi-st" id="yiyi-158">有关使用示例,请参见<a class="reference internal" href="#pickle-dispatch"><span>Dispatch Tables</span></a>。</span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-159"><span class="versionmodified">版本3.3中的新功能。</span></span></p></div></dd></dl><dl class="attribute"><dt id="pickle.Pickler.fast"><span class="yiyi-st" id="yiyi-160"> <code class="descname">fast</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-161">已弃用。</span><span class="yiyi-st" id="yiyi-162">如果设置为true值,请启用快速模式。</span><span class="yiyi-st" id="yiyi-163">快速模式禁用备忘录的使用,因此通过不生成多余的PUT操作码来加速酸洗过程。</span><span class="yiyi-st" id="yiyi-164">它不应该与自引用对象一起使用,否则会导致<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">Pickler</span></code></a>无限递归。</span></p><p><span class="yiyi-st" id="yiyi-165">如果您需要更多的小型泡菜,请使用<a class="reference internal" href="pickletools.html#pickletools.optimize" title="pickletools.optimize"><code class="xref py py-func docutils literal"><span class="pre">pickletools.optimize()</span></code></a>。</span></p></dd></dl></dd></dl><dl class="class"><dt id="pickle.Unpickler"><span class="yiyi-st" id="yiyi-166"> <em class="property">class </em><code class="descclassname">pickle.</code><code class="descname">Unpickler</code><span class="sig-paren">(</span><em>file</em>, <em>*</em>, <em>fix_imports=True</em>, <em>encoding="ASCII"</em>, <em>errors="strict"</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-167">这需要一个二进制文件来读取pickle数据流。</span></p><p><span class="yiyi-st" id="yiyi-168">腌汁的协议版本被自动检测,因此不需要协议参数。</span></p><p><span class="yiyi-st" id="yiyi-169">参数<em>文件</em>必须有两个方法,一个读取整数参数的read()方法和一个不需要参数的readline()方法。</span><span class="yiyi-st" id="yiyi-170">这两种方法都应该返回字节。</span><span class="yiyi-st" id="yiyi-171">因此,<em>文件</em>可以是为二进制读取打开的磁盘文件对象,<a class="reference internal" href="io.html#io.BytesIO" title="io.BytesIO"><code class="xref py py-class docutils literal"><span class="pre">io.BytesIO</span></code></a>对象或满足此接口的任何其他自定义对象。</span></p><p><span class="yiyi-st" id="yiyi-172">可选的关键字参数是<em>fix_imports</em>,<em>编码</em>和<em>错误</em>,用于控制Python 2生成的pickle流的兼容性支持。</span><span class="yiyi-st" id="yiyi-173">如果<em>fix_imports</em>为true,pickle将尝试将旧的Python 2名称映射到Python 3中使用的新名称。</span><span class="yiyi-st" id="yiyi-174"><em>编码</em>和<em>错误</em>告诉pickle如何解码由Python 2 pickled的8位字符串实例;这些默认分别为'ASCII'和'strict'。</span><span class="yiyi-st" id="yiyi-175"><em>编码</em>可以是“bytes”,以将这些ß8位字符串实例读取为字节对象。</span></p><dl class="method"><dt id="pickle.Unpickler.load"><span class="yiyi-st" id="yiyi-176"> <code class="descname">load</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-177">从构造函数中给出的打开文件对象中读取一个腌制对象表示,并返回其中指定的重构对象层次结构。</span><span class="yiyi-st" id="yiyi-178">超过腌制对象表示的字节将被忽略。</span></p></dd></dl><dl class="method"><dt id="pickle.Unpickler.persistent_load"><span class="yiyi-st" id="yiyi-179"> <code class="descname">persistent_load</code><span class="sig-paren">(</span><em>pid</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-180">默认情况下引发<a class="reference internal" href="#pickle.UnpicklingError" title="pickle.UnpicklingError"><code class="xref py py-exc docutils literal"><span class="pre">UnpicklingError</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-181">如果已定义,<a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal"><span class="pre">persistent_load()</span></code></a>应返回持久性标识<em>pid</em>指定的对象。</span><span class="yiyi-st" id="yiyi-182">如果遇到无效的持久性ID,应提出<a class="reference internal" href="#pickle.UnpicklingError" title="pickle.UnpicklingError"><code class="xref py py-exc docutils literal"><span class="pre">UnpicklingError</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-183">有关使用的详细信息和示例,请参见<a class="reference internal" href="#pickle-persistent"><span>Persistence of External Objects</span></a>。</span></p></dd></dl><dl class="method"><dt id="pickle.Unpickler.find_class"><span class="yiyi-st" id="yiyi-184"> <code class="descname">find_class</code><span class="sig-paren">(</span><em>module</em>, <em>name</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-185">如有必要,请输入<em>模块</em>,并返回<em>名称</em>的对象,其中<em>模块</em>和<em>名称</em>参数<a class="reference internal" href="stdtypes.html#str" title="str"><code class="xref py py-class docutils literal"><span class="pre">str</span></code></a>对象。</span><span class="yiyi-st" id="yiyi-186">注意,与其名称不同,<a class="reference internal" href="#pickle.Unpickler.find_class" title="pickle.Unpickler.find_class"><code class="xref py py-meth docutils literal"><span class="pre">find_class()</span></code></a>也用于查找函数。</span></p><p><span class="yiyi-st" id="yiyi-187">子类可以覆盖此类,以获得对什么类型的对象以及如何加载它们的控制,从而潜在地降低安全风险。</span><span class="yiyi-st" id="yiyi-188">有关详细信息,请参阅<a class="reference internal" href="#pickle-restrict"><span>Restricting Globals</span></a>。</span></p></dd></dl></dd></dl></div><div class="section" id="what-can-be-pickled-and-unpickled"><h2><span class="yiyi-st" id="yiyi-189">12.1.4.</span><span class="yiyi-st" id="yiyi-190">什么可以pickled和unpickled?</span></h2><p><span class="yiyi-st" id="yiyi-191">以下类型可以选择:</span></p><ul class="simple"><li><span class="yiyi-st" id="yiyi-192"><code class="docutils literal"><span class="pre">None</span></code>, <code class="docutils literal"><span class="pre">True</span></code>, and <code class="docutils literal"><span class="pre">False</span></code></span></li><li><span class="yiyi-st" id="yiyi-193">整数,浮点数,复数</span></li><li><span class="yiyi-st" id="yiyi-194">字符串,字节,字节数</span></li><li><span class="yiyi-st" id="yiyi-195">元组,列表,集合和仅包含可拾取对象的字典</span></li><li><span class="yiyi-st" id="yiyi-196">在模块顶层定义的函数(使用<a class="reference internal" href="../reference/compound_stmts.html#def"><code class="xref std std-keyword docutils literal"><span class="pre">def</span></code></a>,而不是<a class="reference internal" href="../reference/expressions.html#lambda"><code class="xref std std-keyword docutils literal"><span class="pre">lambda</span></code></a>)</span></li><li><span class="yiyi-st" id="yiyi-197">内建函数定义在模块的顶层</span></li><li><span class="yiyi-st" id="yiyi-198">在模块的顶层定义的类</span></li><li><span class="yiyi-st" id="yiyi-199">其类<a class="reference internal" href="stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal"><span class="pre">__dict__</span></code></a>或调用<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal"><span class="pre">__getstate__()</span></code></a>的类的实例是可选的(有关详细信息,请参阅<a class="reference internal" href="#pickle-inst"><span>Pickling Class Instances</span></a>一节)。</span></li></ul><p><span class="yiyi-st" id="yiyi-200">尝试pickle unpicklable对象将引发<a class="reference internal" href="#pickle.PicklingError" title="pickle.PicklingError"><code class="xref py py-exc docutils literal"><span class="pre">PicklingError</span></code></a>异常;当发生这种情况时,未指定数量的字节可能已经被写入底层文件。</span><span class="yiyi-st" id="yiyi-201">尝试挑选高度递归的数据结构可能会超过最大递归深度,在这种情况下会出现<a class="reference internal" href="exceptions.html#RecursionError" title="RecursionError"><code class="xref py py-exc docutils literal"><span class="pre">RecursionError</span></code></a>。</span><span class="yiyi-st" id="yiyi-202">您可以使用<a class="reference internal" href="sys.html#sys.setrecursionlimit" title="sys.setrecursionlimit"><code class="xref py py-func docutils literal"><span class="pre">sys.setrecursionlimit()</span></code></a>仔细引用此限制。</span></p><p><span class="yiyi-st" id="yiyi-203">注意,函数(内建和用户定义)由“完全限定”名称引用而不是值。</span><span class="yiyi-st" id="yiyi-204"><a class="footnote-reference" href="#id7" id="id2">[2]</a>这意味着只有函数名称被pickled,以及函数定义的模块的名称。</span><span class="yiyi-st" id="yiyi-205">函数的代码,或者它的任何函数属性都没有被腌制。</span><span class="yiyi-st" id="yiyi-206">因此,定义模块必须在unpickling环境中是可导入的,并且模块必须包含命名对象,否则将引发异常。</span><span class="yiyi-st" id="yiyi-207"><a class="footnote-reference" href="#id8" id="id3">[3]</a></span></p><p><span class="yiyi-st" id="yiyi-208">类似地,类通过命名引用进行选择,因此在取消取消环境中应用相同的限制。</span><span class="yiyi-st" id="yiyi-209">请注意,没有类的代码或数据被pickle,因此在下面的示例中,类属性<code class="docutils literal"><span class="pre">attr</span></code>不会在unpickling环境中恢复:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">Foo</span><span class="p">:</span>
|
||
<span class="n">attr</span> <span class="o">=</span> <span class="s1">'A class attribute'</span>
|
||
|
||
<span class="n">picklestring</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">Foo</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-210">这些限制是为什么picklable函数和类必须在模块的顶层定义。</span></p><p><span class="yiyi-st" id="yiyi-211">类似地,当类实例被pickled时,它们的类的代码和数据不与它们一起被腌制。</span><span class="yiyi-st" id="yiyi-212">只有实例数据被酸洗。</span><span class="yiyi-st" id="yiyi-213">这是有意的,所以你可以修复类中的错误或添加方法到类,并仍然加载的对象,使用早期版本的类创建的。</span><span class="yiyi-st" id="yiyi-214">如果你计划有长生命的对象将看到一个类的许多版本,可能值得把一个版本号放在对象中,以便可以通过类的<a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal"><span class="pre">__setstate__()</span></code></a>方法。</span></p></div><div class="section" id="pickling-class-instances"><h2><span class="yiyi-st" id="yiyi-215">12.1.5.</span><span class="yiyi-st" id="yiyi-216">pickling类实例</span></h2><p><span class="yiyi-st" id="yiyi-217">在本节中,我们将描述可用于定义,自定义和控制类实例如何被pickled和unpickled的一般机制。</span></p><p><span class="yiyi-st" id="yiyi-218">在大多数情况下,不需要额外的代码来使实例可拾取。</span><span class="yiyi-st" id="yiyi-219">默认情况下,pickle将通过内省检索实例的类和属性。</span><span class="yiyi-st" id="yiyi-220">当类实例取消取消时,其<a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal"><span class="pre">__init__()</span></code></a>方法通常<em>不</em>被调用。</span><span class="yiyi-st" id="yiyi-221">默认行为首先创建未初始化的实例,然后恢复保存的属性。</span><span class="yiyi-st" id="yiyi-222">以下代码显示了此行为的实现:</span></p><pre><code class="language-python"><span></span><span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">__class__</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">__dict__</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">attributes</span><span class="p">):</span>
|
||
<span class="n">obj</span> <span class="o">=</span> <span class="n">cls</span><span class="o">.</span><span class="n">__new__</span><span class="p">(</span><span class="n">cls</span><span class="p">)</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">attributes</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="n">obj</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-223">类可以通过提供一个或多个特殊方法来更改默认行为:</span></p><dl class="method"><dt id="object.__getnewargs_ex__"><span class="yiyi-st" id="yiyi-224"> <code class="descclassname">object.</code><code class="descname">__getnewargs_ex__</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-225">在协议4和更新版本中,实现<a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs_ex__()</span></code></a>方法的类可以规定在取消发送时传递给<a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal"><span class="pre">__new__()</span></code></a>方法的值。</span><span class="yiyi-st" id="yiyi-226">该方法必须返回一对<code class="docutils literal"><span class="pre">(args,</span> <span class="pre">kwargs)</span></code>其中<em>args</em>是位置参数的元组,<em> kwargs</em>用于构造对象的命名参数的字典。</span><span class="yiyi-st" id="yiyi-227">这些将在解压缩后传递给<a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal"><span class="pre">__new__()</span></code></a>方法。</span></p><p><span class="yiyi-st" id="yiyi-228">如果类的<a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal"><span class="pre">__new__()</span></code></a>方法需要仅限关键字的参数,则应实现此方法。</span><span class="yiyi-st" id="yiyi-229">否则,建议兼容性实现<a class="reference internal" href="#object.__getnewargs__" title="object.__getnewargs__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs__()</span></code></a>。</span></p></dd></dl><dl class="method"><dt id="object.__getnewargs__"><span class="yiyi-st" id="yiyi-230"> <code class="descclassname">object.</code><code class="descname">__getnewargs__</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-231">此方法的作用与<a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs_ex__()</span></code></a>类似,但适用于协议2和更高版本。</span><span class="yiyi-st" id="yiyi-232">它必须返回一个参数<code class="docutils literal"><span class="pre">args</span></code>的元组,它将在取消发送时传递给<a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal"><span class="pre">__new__()</span></code></a>方法。</span></p><p><span class="yiyi-st" id="yiyi-233">在协议4和更新版本中,如果定义<a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs_ex__()</span></code></a>,则不会调用<a class="reference internal" href="#object.__getnewargs__" title="object.__getnewargs__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs__()</span></code></a></span></p></dd></dl><dl class="method"><dt id="object.__getstate__"><span class="yiyi-st" id="yiyi-234"> <code class="descclassname">object.</code><code class="descname">__getstate__</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-235">类可以进一步影响他们的实例如何被酸洗;如果类定义了方法<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal"><span class="pre">__getstate__()</span></code></a>,它被调用,返回的对象被作为实例的内容而不是实例的字典的内容。</span><span class="yiyi-st" id="yiyi-236">如果<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal"><span class="pre">__getstate__()</span></code></a>方法不存在,实例的<a class="reference internal" href="stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal"><span class="pre">__dict__</span></code></a>将像往常一样被腌制。</span></p></dd></dl><dl class="method"><dt id="object.__setstate__"><span class="yiyi-st" id="yiyi-237"> <code class="descclassname">object.</code><code class="descname">__setstate__</code><span class="sig-paren">(</span><em>state</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-238">取消绑定后,如果类定义<a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal"><span class="pre">__setstate__()</span></code></a>,则以unpickled状态调用。</span><span class="yiyi-st" id="yiyi-239">在这种情况下,不需要状态对象是字典。</span><span class="yiyi-st" id="yiyi-240">否则,腌制状态必须是字典,其项目被分配给新实例的字典。</span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-241">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-242">如果<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal"><span class="pre">__getstate__()</span></code></a>返回一个假值,则在取消冻结时不会调用<a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal"><span class="pre">__setstate__()</span></code></a>方法。</span></p></div></dd></dl><p><span class="yiyi-st" id="yiyi-243">有关如何使用方法<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal"><span class="pre">__getstate__()</span></code></a>和<a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal"><span class="pre">__setstate__()</span></code></a>的详细信息,请参阅<a class="reference internal" href="#pickle-state"><span>Handling Stateful Objects</span></a></span></p><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-244">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-245">在取消时间,可以在实例上调用诸如<a class="reference internal" href="../reference/datamodel.html#object.__getattr__" title="object.__getattr__"><code class="xref py py-meth docutils literal"><span class="pre">__getattr__()</span></code></a>,<a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><code class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></code></a>或<a class="reference internal" href="../reference/datamodel.html#object.__setattr__" title="object.__setattr__"><code class="xref py py-meth docutils literal"><span class="pre">__setattr__()</span></code></a></span><span class="yiyi-st" id="yiyi-246">如果这些方法依赖于一些内部不变量为真,则类型应该实现<a class="reference internal" href="#object.__getnewargs__" title="object.__getnewargs__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs__()</span></code></a>或<a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs_ex__()</span></code></a>以建立这样的不变量;否则,将不会调用<a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal"><span class="pre">__new__()</span></code></a>或<a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal"><span class="pre">__init__()</span></code></a>。</span></p></div><p id="index-4"><span class="yiyi-st" id="yiyi-247">正如我们将看到的,pickle不直接使用上述方法。</span><span class="yiyi-st" id="yiyi-248">实际上,这些方法是实现<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce__()</span></code></a>特殊方法的复制协议的一部分。</span><span class="yiyi-st" id="yiyi-249">复制协议提供用于检索对对象进行酸洗和复制所必需的数据的统一接口。</span><span class="yiyi-st" id="yiyi-250"><a class="footnote-reference" href="#id9" id="id4">[4]</a></span></p><p><span class="yiyi-st" id="yiyi-251">虽然功能强大,但直接在类中实现<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce__()</span></code></a>是容易出错的。</span><span class="yiyi-st" id="yiyi-252">为此,类设计器应该使用高级接口(即<a class="reference internal" href="#object.__getnewargs_ex__" title="object.__getnewargs_ex__"><code class="xref py py-meth docutils literal"><span class="pre">__getnewargs_ex__()</span></code></a>,<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal"><span class="pre">__getstate__()</span></code></a>和<a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal"><span class="pre">__setstate__()</span></code></a>)可能。</span><span class="yiyi-st" id="yiyi-253">然而,我们将展示使用<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce__()</span></code></a>是唯一选项,或者导致更有效的酸洗或两者兼而有之的情况。</span></p><dl class="method"><dt id="object.__reduce__"><span class="yiyi-st" id="yiyi-254"> <code class="descclassname">object.</code><code class="descname">__reduce__</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-255">该接口当前定义如下。</span><span class="yiyi-st" id="yiyi-256"><a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce__()</span></code></a>方法不带参数,应返回字符串或最好是一个元组(返回的对象通常称为“减少值”)。</span></p><p><span class="yiyi-st" id="yiyi-257">如果返回一个字符串,该字符串应该被解释为全局变量的名称。</span><span class="yiyi-st" id="yiyi-258">它应该是对象相对于其模块的本地名称; pickle模块搜索模块命名空间以确定对象的模块。</span><span class="yiyi-st" id="yiyi-259">此行为通常对单例有用。</span></p><p><span class="yiyi-st" id="yiyi-260">当返回一个元组时,它必须在两到五个项之间。</span><span class="yiyi-st" id="yiyi-261">可以省略可选项,也可以提供<code class="docutils literal"><span class="pre">None</span></code>作为其值。</span><span class="yiyi-st" id="yiyi-262">每个项目的语义是按顺序:</span></p><ul class="simple"><li><span class="yiyi-st" id="yiyi-263">将被调用以创建对象的初始版本的可调用对象。</span></li><li><span class="yiyi-st" id="yiyi-264">可调用对象的参数的元组。</span><span class="yiyi-st" id="yiyi-265">如果callable不接受任何参数,则必须给出一个空元组。</span></li><li><span class="yiyi-st" id="yiyi-266">可选地,对象的状态将被传递到对象的<a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal"><span class="pre">__setstate__()</span></code></a>方法,如前所述。</span><span class="yiyi-st" id="yiyi-267">如果对象没有这样的方法,那么值必须是字典,并且它将被添加到对象的<a class="reference internal" href="stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal"><span class="pre">__dict__</span></code></a>属性。</span></li><li><span class="yiyi-st" id="yiyi-268">可选地,迭代器(而不是序列)产生连续项。</span><span class="yiyi-st" id="yiyi-269">这些项将使用<code class="docutils literal"><span class="pre">obj.append(item)</span></code>或批量使用<code class="docutils literal"><span class="pre">obj.extend(list_of_items)</span></code>附加到对象。</span><span class="yiyi-st" id="yiyi-270">这主要用于列表子类,但可以由其他类使用,只要它们具有适当的声明的<code class="xref py py-meth docutils literal"><span class="pre">append()</span></code>和<code class="xref py py-meth docutils literal"><span class="pre">extend()</span></code>方法。</span><span class="yiyi-st" id="yiyi-271">(是否使用<code class="xref py py-meth docutils literal"><span class="pre">append()</span></code>或<code class="xref py py-meth docutils literal"><span class="pre">extend()</span></code>取决于使用的pickle协议版本以及要附加的项目数,因此必须支持两者。</span></li><li><span class="yiyi-st" id="yiyi-272">可选地,产生连续键值对的迭代器(而不是序列)。</span><span class="yiyi-st" id="yiyi-273">这些项将使用<code class="docutils literal"><span class="pre">obj [key]</span> <span class="pre">=</span> <span class="pre">值</span></code>存储到对象。</span><span class="yiyi-st" id="yiyi-274">这主要用于字典子类,但可以由其他类使用,只要它们实现<a class="reference internal" href="../reference/datamodel.html#object.__setitem__" title="object.__setitem__"><code class="xref py py-meth docutils literal"><span class="pre">__setitem__()</span></code></a>。</span></li></ul></dd></dl><dl class="method"><dt id="object.__reduce_ex__"><span class="yiyi-st" id="yiyi-275"> <code class="descclassname">object.</code><code class="descname">__reduce_ex__</code><span class="sig-paren">(</span><em>protocol</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-276">或者,可以定义<a class="reference internal" href="#object.__reduce_ex__" title="object.__reduce_ex__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce_ex__()</span></code></a>方法。</span><span class="yiyi-st" id="yiyi-277">唯一的区别是这个方法应该采用单个整数参数,即协议版本。</span><span class="yiyi-st" id="yiyi-278">当定义时,pickle将优先于<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce__()</span></code></a>方法。</span><span class="yiyi-st" id="yiyi-279">此外,<a class="reference internal" href="#object.__reduce__" title="object.__reduce__"><code class="xref py py-meth docutils literal"><span class="pre">__reduce__()</span></code></a>自动成为扩展版本的同义词。</span><span class="yiyi-st" id="yiyi-280">此方法的主要用途是为较早的Python版本提供向后兼容的reduce值。</span></p></dd></dl><div class="section" id="persistence-of-external-objects"><h3><span class="yiyi-st" id="yiyi-281">12.1.5.1.</span><span class="yiyi-st" id="yiyi-282">外部对象的持久性</span></h3><p id="index-5"><span class="yiyi-st" id="yiyi-283">为了对象持久化的益处,<a class="reference internal" href="#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-284">这样的对象由持久性ID引用,持久性ID应为字母数字字符(对于协议0)<a class="footnote-reference" href="#id10" id="id5">[5]</a>的字符串,或者只是任意对象(对于任何较新的协议)。</span></p><p><span class="yiyi-st" id="yiyi-285">这种持久性ID的解析不是由<a class="reference internal" href="#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>模块定义的;它将分别将此解决方案委托给pickler和unpickler上的用户定义的方法<a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal"><span class="pre">persistent_id()</span></code></a>和<a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal"><span class="pre">persistent_load()</span></code></a>。</span></p><p><span class="yiyi-st" id="yiyi-286">要选择具有外部持久性标识的对象,pickler必须有一个自定义的<a class="reference internal" href="#pickle.Pickler.persistent_id" title="pickle.Pickler.persistent_id"><code class="xref py py-meth docutils literal"><span class="pre">persistent_id()</span></code></a>方法,它将一个对象作为参数,并返回<code class="docutils literal"><span class="pre">None</span></code>那个对象。</span><span class="yiyi-st" id="yiyi-287">当返回<code class="docutils literal"><span class="pre">None</span></code>时,pickler只是像正常一样腌制对象。</span><span class="yiyi-st" id="yiyi-288">当返回持久性ID字符串时,pickler将拾取该对象以及一个标记,以便unpickler将它识别为持久性ID。</span></p><p><span class="yiyi-st" id="yiyi-289">要取消取消外部对象,取消管理器必须有一个自定义<a class="reference internal" href="#pickle.Unpickler.persistent_load" title="pickle.Unpickler.persistent_load"><code class="xref py py-meth docutils literal"><span class="pre">persistent_load()</span></code></a>方法,该方法需要持久的ID对象并返回引用的对象。</span></p><p><span class="yiyi-st" id="yiyi-290">这里是一个综合示例,介绍如何使用持久性标识来引用外部对象。</span></p><pre><code class="language-python"><span></span><span class="c1"># Simple example presenting how persistent ID can be used to pickle</span>
|
||
<span class="c1"># external objects by reference.</span>
|
||
|
||
<span class="kn">import</span> <span class="nn">pickle</span>
|
||
<span class="kn">import</span> <span class="nn">sqlite3</span>
|
||
<span class="kn">from</span> <span class="nn">collections</span> <span class="k">import</span> <span class="n">namedtuple</span>
|
||
|
||
<span class="c1"># Simple class representing a record in our database.</span>
|
||
<span class="n">MemoRecord</span> <span class="o">=</span> <span class="n">namedtuple</span><span class="p">(</span><span class="s2">"MemoRecord"</span><span class="p">,</span> <span class="s2">"key, task"</span><span class="p">)</span>
|
||
|
||
<span class="k">class</span> <span class="nc">DBPickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">persistent_id</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||
<span class="c1"># Instead of pickling MemoRecord as a regular class instance, we emit a</span>
|
||
<span class="c1"># persistent ID.</span>
|
||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">MemoRecord</span><span class="p">):</span>
|
||
<span class="c1"># Here, our persistent ID is simply a tuple, containing a tag and a</span>
|
||
<span class="c1"># key, which refers to a specific record in the database.</span>
|
||
<span class="k">return</span> <span class="p">(</span><span class="s2">"MemoRecord"</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># If obj does not have a persistent ID, return None. This means obj</span>
|
||
<span class="c1"># needs to be pickled as usual.</span>
|
||
<span class="k">return</span> <span class="kc">None</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">DBUnpickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Unpickler</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">file</span><span class="p">,</span> <span class="n">connection</span><span class="p">):</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="n">file</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">connection</span> <span class="o">=</span> <span class="n">connection</span>
|
||
|
||
<span class="k">def</span> <span class="nf">persistent_load</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">pid</span><span class="p">):</span>
|
||
<span class="c1"># This method is invoked whenever a persistent ID is encountered.</span>
|
||
<span class="c1"># Here, pid is the tuple returned by DBPickler.</span>
|
||
<span class="n">cursor</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">connection</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
|
||
<span class="n">type_tag</span><span class="p">,</span> <span class="n">key_id</span> <span class="o">=</span> <span class="n">pid</span>
|
||
<span class="k">if</span> <span class="n">type_tag</span> <span class="o">==</span> <span class="s2">"MemoRecord"</span><span class="p">:</span>
|
||
<span class="c1"># Fetch the referenced record from the database and return it.</span>
|
||
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"SELECT * FROM memos WHERE key=?"</span><span class="p">,</span> <span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">key_id</span><span class="p">),))</span>
|
||
<span class="n">key</span><span class="p">,</span> <span class="n">task</span> <span class="o">=</span> <span class="n">cursor</span><span class="o">.</span><span class="n">fetchone</span><span class="p">()</span>
|
||
<span class="k">return</span> <span class="n">MemoRecord</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">task</span><span class="p">)</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="c1"># Always raises an error if you cannot return the correct object.</span>
|
||
<span class="c1"># Otherwise, the unpickler will think None is the object referenced</span>
|
||
<span class="c1"># by the persistent ID.</span>
|
||
<span class="k">raise</span> <span class="n">pickle</span><span class="o">.</span><span class="n">UnpicklingError</span><span class="p">(</span><span class="s2">"unsupported persistent object"</span><span class="p">)</span>
|
||
|
||
|
||
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
|
||
<span class="kn">import</span> <span class="nn">io</span>
|
||
<span class="kn">import</span> <span class="nn">pprint</span>
|
||
|
||
<span class="c1"># Initialize and populate our database.</span>
|
||
<span class="n">conn</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">":memory:"</span><span class="p">)</span>
|
||
<span class="n">cursor</span> <span class="o">=</span> <span class="n">conn</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span>
|
||
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)"</span><span class="p">)</span>
|
||
<span class="n">tasks</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="s1">'give food to fish'</span><span class="p">,</span>
|
||
<span class="s1">'prepare group meeting'</span><span class="p">,</span>
|
||
<span class="s1">'fight with a zebra'</span><span class="p">,</span>
|
||
<span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">tasks</span><span class="p">:</span>
|
||
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"INSERT INTO memos VALUES(NULL, ?)"</span><span class="p">,</span> <span class="p">(</span><span class="n">task</span><span class="p">,))</span>
|
||
|
||
<span class="c1"># Fetch the records to be pickled.</span>
|
||
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"SELECT * FROM memos"</span><span class="p">)</span>
|
||
<span class="n">memos</span> <span class="o">=</span> <span class="p">[</span><span class="n">MemoRecord</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">task</span><span class="p">)</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">cursor</span><span class="p">]</span>
|
||
<span class="c1"># Save the records using our custom DBPickler.</span>
|
||
<span class="n">file</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
|
||
<span class="n">DBPickler</span><span class="p">(</span><span class="n">file</span><span class="p">)</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">memos</span><span class="p">)</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Pickled records:"</span><span class="p">)</span>
|
||
<span class="n">pprint</span><span class="o">.</span><span class="n">pprint</span><span class="p">(</span><span class="n">memos</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Update a record, just for good measure.</span>
|
||
<span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s2">"UPDATE memos SET task='learn italian' WHERE key=1"</span><span class="p">)</span>
|
||
|
||
<span class="c1"># Load the records from the pickle data stream.</span>
|
||
<span class="n">file</span><span class="o">.</span><span class="n">seek</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||
<span class="n">memos</span> <span class="o">=</span> <span class="n">DBUnpickler</span><span class="p">(</span><span class="n">file</span><span class="p">,</span> <span class="n">conn</span><span class="p">)</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Unpickled records:"</span><span class="p">)</span>
|
||
<span class="n">pprint</span><span class="o">.</span><span class="n">pprint</span><span class="p">(</span><span class="n">memos</span><span class="p">)</span>
|
||
|
||
|
||
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s1">'__main__'</span><span class="p">:</span>
|
||
<span class="n">main</span><span class="p">()</span>
|
||
</code></pre></div><div class="section" id="dispatch-tables"><h3><span class="yiyi-st" id="yiyi-291">12.1.5.2.</span><span class="yiyi-st" id="yiyi-292">Dispatch Tables</span></h3><p><span class="yiyi-st" id="yiyi-293">如果想要定制一些类的pickling而不干扰依赖于pickling的任何其他代码,那么可以创建一个带有私有调度表的pickler。</span></p><p><span class="yiyi-st" id="yiyi-294">由<a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal"><span class="pre">copyreg</span></code></a>模块管理的全局分派表可用作<code class="xref py py-data docutils literal"><span class="pre">copyreg.dispatch_table</span></code>。</span><span class="yiyi-st" id="yiyi-295">因此,可以选择使用<code class="xref py py-data docutils literal"><span class="pre">copyreg.dispatch_table</span></code>的修改副本作为专用分派表。</span></p><p><span class="yiyi-st" id="yiyi-296">例如</span></p><pre><code class="language-python"><span></span><span class="n">f</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
|
||
<span class="n">p</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||
<span class="n">p</span><span class="o">.</span><span class="n">dispatch_table</span> <span class="o">=</span> <span class="n">copyreg</span><span class="o">.</span><span class="n">dispatch_table</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||
<span class="n">p</span><span class="o">.</span><span class="n">dispatch_table</span><span class="p">[</span><span class="n">SomeClass</span><span class="p">]</span> <span class="o">=</span> <span class="n">reduce_SomeClass</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-297">使用专用处理<code class="docutils literal"><span class="pre">SomeClass</span></code>类的专用分派表创建<a class="reference internal" href="#pickle.Pickler" title="pickle.Pickler"><code class="xref py py-class docutils literal"><span class="pre">pickle.Pickler</span></code></a>的实例。</span><span class="yiyi-st" id="yiyi-298">或者,代码</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">MyPickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">):</span>
|
||
<span class="n">dispatch_table</span> <span class="o">=</span> <span class="n">copyreg</span><span class="o">.</span><span class="n">dispatch_table</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||
<span class="n">dispatch_table</span><span class="p">[</span><span class="n">SomeClass</span><span class="p">]</span> <span class="o">=</span> <span class="n">reduce_SomeClass</span>
|
||
<span class="n">f</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
|
||
<span class="n">p</span> <span class="o">=</span> <span class="n">MyPickler</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-299">但是所有实例<code class="docutils literal"><span class="pre">MyPickler</span></code>将默认共享相同的分派表。</span><span class="yiyi-st" id="yiyi-300">使用<a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal"><span class="pre">copyreg</span></code></a>模块的等效代码为</span></p><pre><code class="language-python"><span></span><span class="n">copyreg</span><span class="o">.</span><span class="n">pickle</span><span class="p">(</span><span class="n">SomeClass</span><span class="p">,</span> <span class="n">reduce_SomeClass</span><span class="p">)</span>
|
||
<span class="n">f</span> <span class="o">=</span> <span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">()</span>
|
||
<span class="n">p</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">Pickler</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||
</code></pre></div><div class="section" id="handling-stateful-objects"><h3><span class="yiyi-st" id="yiyi-301">12.1.5.3.</span><span class="yiyi-st" id="yiyi-302">处理状态对象</span></h3><p id="index-6"><span class="yiyi-st" id="yiyi-303">这里有一个例子演示如何修改类的酸洗行为。</span><span class="yiyi-st" id="yiyi-304"><code class="xref py py-class docutils literal"><span class="pre">TextReader</span></code>类打开一个文本文件,并在每次调用<code class="xref py py-meth docutils literal"><span class="pre">readline()</span></code>方法时返回行号和行内容。</span><span class="yiyi-st" id="yiyi-305">如果<code class="xref py py-class docutils literal"><span class="pre">TextReader</span></code>实例被选中,除了文件对象成员的所有属性<em>都被保存。</em></span><span class="yiyi-st" id="yiyi-306">当实例取消选中时,文件将重新打开,并从最后一个位置继续读取。</span><span class="yiyi-st" id="yiyi-307"><a class="reference internal" href="#object.__setstate__" title="object.__setstate__"><code class="xref py py-meth docutils literal"><span class="pre">__setstate__()</span></code></a>和<a class="reference internal" href="#object.__getstate__" title="object.__getstate__"><code class="xref py py-meth docutils literal"><span class="pre">__getstate__()</span></code></a>方法用于实现此行为。</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">TextReader</span><span class="p">:</span>
|
||
<span class="sd">"""Print and number lines in a text file."""</span>
|
||
|
||
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">filename</span> <span class="o">=</span> <span class="n">filename</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">lineno</span> <span class="o">=</span> <span class="mi">0</span>
|
||
|
||
<span class="k">def</span> <span class="nf">readline</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">lineno</span> <span class="o">+=</span> <span class="mi">1</span>
|
||
<span class="n">line</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">file</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">line</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="kc">None</span>
|
||
<span class="k">if</span> <span class="n">line</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">'</span><span class="se">\n</span><span class="s1">'</span><span class="p">):</span>
|
||
<span class="n">line</span> <span class="o">=</span> <span class="n">line</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
|
||
<span class="k">return</span> <span class="s2">"</span><span class="si">%i</span><span class="s2">: </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lineno</span><span class="p">,</span> <span class="n">line</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">__getstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># Copy the object's state from self.__dict__ which contains</span>
|
||
<span class="c1"># all our instance attributes. Always use the dict.copy()</span>
|
||
<span class="c1"># method to avoid modifying the original state.</span>
|
||
<span class="n">state</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
|
||
<span class="c1"># Remove the unpicklable entries.</span>
|
||
<span class="k">del</span> <span class="n">state</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span>
|
||
<span class="k">return</span> <span class="n">state</span>
|
||
|
||
<span class="k">def</span> <span class="nf">__setstate__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">state</span><span class="p">):</span>
|
||
<span class="c1"># Restore instance attributes (i.e., filename and lineno).</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">__dict__</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">state</span><span class="p">)</span>
|
||
<span class="c1"># Restore the previously opened file's state. To do so, we need to</span>
|
||
<span class="c1"># reopen it and read from it until the line count is restored.</span>
|
||
<span class="n">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span>
|
||
<span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lineno</span><span class="p">):</span>
|
||
<span class="n">file</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
|
||
<span class="c1"># Finally, save the file.</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">file</span> <span class="o">=</span> <span class="n">file</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-308">示例用法可能如下所示:</span></p><pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">reader</span> <span class="o">=</span> <span class="n">TextReader</span><span class="p">(</span><span class="s2">"hello.txt"</span><span class="p">)</span>
|
||
<span class="gp">>>> </span><span class="n">reader</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
|
||
<span class="go">'1: Hello world!'</span>
|
||
<span class="gp">>>> </span><span class="n">reader</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
|
||
<span class="go">'2: I am line number two.'</span>
|
||
<span class="gp">>>> </span><span class="n">new_reader</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">reader</span><span class="p">))</span>
|
||
<span class="gp">>>> </span><span class="n">new_reader</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
|
||
<span class="go">'3: Goodbye!'</span>
|
||
</code></pre></div></div><div class="section" id="restricting-globals"><h2><span class="yiyi-st" id="yiyi-309">12.1.6.</span><span class="yiyi-st" id="yiyi-310">限制全局变量</span></h2><p id="index-7"><span class="yiyi-st" id="yiyi-311">默认情况下,unpickling将导入它在pickle数据中找到的任何类或函数。</span><span class="yiyi-st" id="yiyi-312">对于许多应用程序,此行为是不可接受的,因为它允许unpickler导入和调用任意代码。</span><span class="yiyi-st" id="yiyi-313">只考虑这个手工制作的pickle数据流加载时:</span></p><pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">pickle</span>
|
||
<span class="gp">>>> </span><span class="n">pickle</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">b</span><span class="s2">"cos</span><span class="se">\n</span><span class="s2">system</span><span class="se">\n</span><span class="s2">(S'echo hello world'</span><span class="se">\n</span><span class="s2">tR."</span><span class="p">)</span>
|
||
<span class="go">hello world</span>
|
||
<span class="go">0</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-314">在此示例中,unpickler导入<a class="reference internal" href="os.html#os.system" title="os.system"><code class="xref py py-func docutils literal"><span class="pre">os.system()</span></code></a>函数,然后应用字符串参数“echo hello world”。</span><span class="yiyi-st" id="yiyi-315">虽然这个例子是不好的,但不难想象会损坏你的系统。</span></p><p><span class="yiyi-st" id="yiyi-316">因此,您可以通过自定义<a class="reference internal" href="#pickle.Unpickler.find_class" title="pickle.Unpickler.find_class"><code class="xref py py-meth docutils literal"><span class="pre">Unpickler.find_class()</span></code></a>来控制取消取消取消的内容。</span><span class="yiyi-st" id="yiyi-317">与其名称不同的是,当请求全局(即类或函数)时,调用<a class="reference internal" href="#pickle.Unpickler.find_class" title="pickle.Unpickler.find_class"><code class="xref py py-meth docutils literal"><span class="pre">Unpickler.find_class()</span></code></a>。</span><span class="yiyi-st" id="yiyi-318">因此,可以完全禁止全局变量或将其限制为安全子集。</span></p><p><span class="yiyi-st" id="yiyi-319">这里有一个unpickler的例子,只允许加载来自<a class="reference internal" href="builtins.html#module-builtins" title="builtins: The module that provides the built-in namespace."><code class="xref py py-mod docutils literal"><span class="pre">builtins</span></code></a>的几个安全类:</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">builtins</span>
|
||
<span class="kn">import</span> <span class="nn">io</span>
|
||
<span class="kn">import</span> <span class="nn">pickle</span>
|
||
|
||
<span class="n">safe_builtins</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s1">'range'</span><span class="p">,</span>
|
||
<span class="s1">'complex'</span><span class="p">,</span>
|
||
<span class="s1">'set'</span><span class="p">,</span>
|
||
<span class="s1">'frozenset'</span><span class="p">,</span>
|
||
<span class="s1">'slice'</span><span class="p">,</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">class</span> <span class="nc">RestrictedUnpickler</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">Unpickler</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">find_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">module</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
|
||
<span class="c1"># Only allow safe classes from builtins.</span>
|
||
<span class="k">if</span> <span class="n">module</span> <span class="o">==</span> <span class="s2">"builtins"</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">safe_builtins</span><span class="p">:</span>
|
||
<span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">builtins</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
|
||
<span class="c1"># Forbid everything else.</span>
|
||
<span class="k">raise</span> <span class="n">pickle</span><span class="o">.</span><span class="n">UnpicklingError</span><span class="p">(</span><span class="s2">"global '</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2">' is forbidden"</span> <span class="o">%</span>
|
||
<span class="p">(</span><span class="n">module</span><span class="p">,</span> <span class="n">name</span><span class="p">))</span>
|
||
|
||
<span class="k">def</span> <span class="nf">restricted_loads</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
|
||
<span class="sd">"""Helper function analogous to pickle.loads()."""</span>
|
||
<span class="k">return</span> <span class="n">RestrictedUnpickler</span><span class="p">(</span><span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">s</span><span class="p">))</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-320">我们的unpickler工作的样例用法:</span></p><pre><code class="language-python"><span></span><span class="gp">>>> </span><span class="n">restricted_loads</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">dumps</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="nb">range</span><span class="p">(</span><span class="mi">15</span><span class="p">)]))</span>
|
||
<span class="go">[1, 2, range(0, 15)]</span>
|
||
<span class="gp">>>> </span><span class="n">restricted_loads</span><span class="p">(</span><span class="n">b</span><span class="s2">"cos</span><span class="se">\n</span><span class="s2">system</span><span class="se">\n</span><span class="s2">(S'echo hello world'</span><span class="se">\n</span><span class="s2">tR."</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
<span class="c">...</span>
|
||
<span class="gr">pickle.UnpicklingError</span>: <span class="n">global 'os.system' is forbidden</span>
|
||
<span class="gp">>>> </span><span class="n">restricted_loads</span><span class="p">(</span><span class="n">b</span><span class="s1">'cbuiltins</span><span class="se">\n</span><span class="s1">eval</span><span class="se">\n</span><span class="s1">'</span>
|
||
<span class="gp">... </span> <span class="n">b</span><span class="s1">'(S</span><span class="se">\'</span><span class="s1">getattr(__import__("os"), "system")'</span>
|
||
<span class="gp">... </span> <span class="n">b</span><span class="s1">'("echo hello world")</span><span class="se">\'\n</span><span class="s1">tR.'</span><span class="p">)</span>
|
||
<span class="gt">Traceback (most recent call last):</span>
|
||
<span class="c">...</span>
|
||
<span class="gr">pickle.UnpicklingError</span>: <span class="n">global 'builtins.eval' is forbidden</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-321">正如我们的例子所示,你必须小心你允许被解冻。</span><span class="yiyi-st" id="yiyi-322">因此,如果担心安全问题,您可能需要考虑替代方案,例如<a class="reference internal" href="xmlrpc.client.html#module-xmlrpc.client" title="xmlrpc.client: XML-RPC client access."><code class="xref py py-mod docutils literal"><span class="pre">xmlrpc.client</span></code></a>中的编组API或第三方解决方案。</span></p></div><div class="section" id="performance"><h2><span class="yiyi-st" id="yiyi-323">12.1.7.</span><span class="yiyi-st" id="yiyi-324">性能</span></h2><p><span class="yiyi-st" id="yiyi-325">最新版本的pickle协议(从协议2及以上版本)为几个常见功能和内建类型提供高效的二进制编码。</span><span class="yiyi-st" id="yiyi-326">此外,<a class="reference internal" href="#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>模块具有以C编写的透明优化程序。</span></p></div><div class="section" id="examples"><h2><span class="yiyi-st" id="yiyi-327">12.1.8.</span><span class="yiyi-st" id="yiyi-328">示例</span></h2><p><span class="yiyi-st" id="yiyi-329">对于最简单的代码,使用<a class="reference internal" href="#pickle.dump" title="pickle.dump"><code class="xref py py-func docutils literal"><span class="pre">dump()</span></code></a>和<a class="reference internal" href="#pickle.load" title="pickle.load"><code class="xref py py-func docutils literal"><span class="pre">load()</span></code></a>函数。</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">pickle</span>
|
||
|
||
<span class="c1"># An arbitrary collection of objects supported by pickle.</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s1">'a'</span><span class="p">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="o">+</span><span class="mi">6</span><span class="n">j</span><span class="p">],</span>
|
||
<span class="s1">'b'</span><span class="p">:</span> <span class="p">(</span><span class="s2">"character string"</span><span class="p">,</span> <span class="n">b</span><span class="s2">"byte string"</span><span class="p">),</span>
|
||
<span class="s1">'c'</span><span class="p">:</span> <span class="p">{</span><span class="kc">None</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="kc">False</span><span class="p">}</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'data.pickle'</span><span class="p">,</span> <span class="s1">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||
<span class="c1"># Pickle the 'data' dictionary using the highest protocol available.</span>
|
||
<span class="n">pickle</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">pickle</span><span class="o">.</span><span class="n">HIGHEST_PROTOCOL</span><span class="p">)</span>
|
||
</code></pre><p><span class="yiyi-st" id="yiyi-330">以下示例读取生成的pickled数据。</span></p><pre><code class="language-python"><span></span><span class="kn">import</span> <span class="nn">pickle</span>
|
||
|
||
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s1">'data.pickle'</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
||
<span class="c1"># The protocol version used is detected automatically, so we do not</span>
|
||
<span class="c1"># have to specify it.</span>
|
||
<span class="n">data</span> <span class="o">=</span> <span class="n">pickle</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
|
||
</code></pre><div class="admonition seealso"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-331">也可以看看</span></p><dl class="last docutils"><dt><span class="yiyi-st" id="yiyi-332">模块<a class="reference internal" href="copyreg.html#module-copyreg" title="copyreg: Register pickle support functions."><code class="xref py py-mod docutils literal"><span class="pre">copyreg</span></code></a></span></dt><dd><span class="yiyi-st" id="yiyi-333">Pickle接口构造函数注册扩展类型。</span></dd><dt><span class="yiyi-st" id="yiyi-334">模块<a class="reference internal" href="pickletools.html#module-pickletools" title="pickletools: Contains extensive comments about the pickle protocols and pickle-machine opcodes, as well as some useful functions."><code class="xref py py-mod docutils literal"><span class="pre">pickletools</span></code></a></span></dt><dd><span class="yiyi-st" id="yiyi-335">用于处理和分析pickled数据的工具。</span></dd><dt><span class="yiyi-st" id="yiyi-336">模块<a class="reference internal" href="shelve.html#module-shelve" title="shelve: Python object persistence."><code class="xref py py-mod docutils literal"><span class="pre">shelve</span></code></a></span></dt><dd><span class="yiyi-st" id="yiyi-337">索引的对象数据库;使用<a class="reference internal" href="#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></dd><dt><span class="yiyi-st" id="yiyi-338">模块<a class="reference internal" href="copy.html#module-copy" title="copy: Shallow and deep copy operations."><code class="xref py py-mod docutils literal"><span class="pre">copy</span></code></a></span></dt><dd><span class="yiyi-st" id="yiyi-339">浅和深对象复制。</span></dd><dt><span class="yiyi-st" id="yiyi-340">模块<a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a></span></dt><dd><span class="yiyi-st" id="yiyi-341">内建类型的高性能序列化。</span></dd></dl></div><p class="rubric"><span class="yiyi-st" id="yiyi-342">脚注</span></p><table class="docutils footnote" frame="void" id="id6" rules="none"><tbody valign="top"><tr><td class="label"><span class="yiyi-st" id="yiyi-343"><a class="fn-backref" href="#id1">[1]</a></span></td><td><span class="yiyi-st" id="yiyi-344">不要将此与<a class="reference internal" href="marshal.html#module-marshal" title="marshal: Convert Python objects to streams of bytes and back (with different constraints)."><code class="xref py py-mod docutils literal"><span class="pre">marshal</span></code></a>模块混淆</span></td></tr></tbody></table><table class="docutils footnote" frame="void" id="id7" rules="none"><tbody valign="top"><tr><td class="label"><span class="yiyi-st" id="yiyi-345"><a class="fn-backref" href="#id2">[2]</a></span></td><td><span class="yiyi-st" id="yiyi-346">这就是为什么<a class="reference internal" href="../reference/expressions.html#lambda"><code class="xref std std-keyword docutils literal"><span class="pre">lambda</span></code></a>函数不能被pickled:所有<a class="reference internal" href="../reference/expressions.html#lambda"><code class="xref std std-keyword docutils literal"><span class="pre">lambda</span></code></a>函数共享同一个名称:<code class="docutils literal"><span class="pre"><lambda></span></code>。</span></td></tr></tbody></table><table class="docutils footnote" frame="void" id="id8" rules="none"><tbody valign="top"><tr><td class="label"><span class="yiyi-st" id="yiyi-347"><a class="fn-backref" href="#id3">[3]</a></span></td><td><span class="yiyi-st" id="yiyi-348">引发的异常可能是<a class="reference internal" href="exceptions.html#ImportError" title="ImportError"><code class="xref py py-exc docutils literal"><span class="pre">ImportError</span></code></a>或<a class="reference internal" href="exceptions.html#AttributeError" title="AttributeError"><code class="xref py py-exc docutils literal"><span class="pre">AttributeError</span></code></a>,但可能是其他原因。</span></td></tr></tbody></table><table class="docutils footnote" frame="void" id="id9" rules="none"><tbody valign="top"><tr><td class="label"><span class="yiyi-st" id="yiyi-349"><a class="fn-backref" href="#id4">[4]</a></span></td><td><span class="yiyi-st" id="yiyi-350"><a class="reference internal" href="copy.html#module-copy" title="copy: Shallow and deep copy operations."><code class="xref py py-mod docutils literal"><span class="pre">copy</span></code></a>模块使用此协议进行浅层和深层复制操作。</span></td></tr></tbody></table><table class="docutils footnote" frame="void" id="id10" rules="none"><tbody valign="top"><tr><td class="label"><span class="yiyi-st" id="yiyi-351"><a class="fn-backref" href="#id5">[5]</a></span></td><td><span class="yiyi-st" id="yiyi-352">对字母数字字符的限制是由于事实,协议0中的持久性ID由换行符字符分隔。</span><span class="yiyi-st" id="yiyi-353">因此,如果在持久性ID中出现任何类型的换行符,则生成的pickle将变得不可读。</span></td></tr></tbody></table></div></div></div> |