<p>我认为假设对象是<code>class</code>是一个相当强的假设。如果不是<code>class</code>呢?还有一个假设是对象没有在解释器中定义。如果它是在解释器中定义的呢?另外,如果属性是动态添加的呢?当一些python对象在创建后将属性添加到它们的<code>__dict__</code>中时,<code>pickle</code>不考虑这些属性的添加(即它“忘记”添加了它们——因为<code>pickle</code>通过引用对象定义序列化)。</p>
<p>在所有这些情况下,<code>pickle</code>和<code>cPickle</code>都会让你非常失望。</p>
<p>如果您希望保存一个<code>object</code>(任意创建),其中有属性(添加到对象定义中或之后)…您最好的选择是使用<code>dill</code>,它可以序列化python中的几乎任何内容。</p>
<p>我们从一节课开始</p>
<pre><code>Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>> with open('company.pkl', 'wb') as f:
... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
</code></pre>
<p>现在关机,重新启动。。。</p>
<pre><code>Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> with open('company.pkl', 'rb') as f:
... company1 = pickle.load(f)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'Company'
>>>
</code></pre>
<p>哎哟……<code>pickle</code>处理不了。让我们试试<code>dill</code>。我们将引入另一个对象类型(a<code>lambda</code>)以获得良好的度量。</p>
<pre><code>Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> with open('company_dill.pkl', 'wb') as f:
... dill.dump(company1, f)
... dill.dump(company2, f)
...
>>>
</code></pre>
<p>现在读一下文件。</p>
<pre><code>Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> with open('company_dill.pkl', 'rb') as f:
... company1 = dill.load(f)
... company2 = dill.load(f)
...
>>> company1
<__main__.Company instance at 0x107909128>
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>>
</code></pre>
<p>它起作用了。<code>pickle</code>失败,而<code>dill</code>不成功的原因是<code>dill</code>将<code>__main__</code>视为一个模块(在大多数情况下),并且还可以pickle类定义,而不是通过引用pickle(就像<code>pickle</code>那样)。之所以<code>dill</code>可以腌制<code>lambda</code>,是因为它给它起了个名字……然后腌制魔法就可以发生。</p>
<p>实际上,有一种更简单的方法保存所有这些对象,特别是如果您已经创建了很多对象。只需转储整个python会话,稍后再返回。</p>
<pre><code>Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
</code></pre>
<p>现在关掉你的电脑,去享受一杯浓咖啡或其他什么,然后回来。。。</p>
<pre><code>Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>> company2
<function <lambda> at 0x1065f2938>
</code></pre>
<p>唯一的主要缺点是<code>dill</code>不是python标准库的一部分。因此,如果不能在服务器上安装python包,就不能使用它。</p>
<p>但是,如果能够在系统上安装python包,则可以使用<code>git+https://github.com/uqfoundation/dill.git@master#egg=dill</code>获得最新的<code>dill</code>。您可以使用<code>pip install dill</code>获得最新发布的版本。</p>