Python pickle调用cPickle?

时间:2015-11-17 00:28:49

标签: python python-3.x intellij-idea pickle

我是Python新手。我正在将其他人的代码从Python 2.X改编为3.5。代码通过cPickle加载文件。我改变了所有" cPickle"发生在" pickle"据我所知,pickle在3.5中取代了cPickle。我得到了这个执行错误:

NameError: name 'cPickle' is not defined

相关代码:

import pickle
import gzip
...
def load_data():
    f = gzip.open('../data/mnist.pkl.gz', 'rb')
    training_data, validation_data, test_data = pickle.load(f, fix_imports=True)
    f.close()
    return (training_data, validation_data, test_data)

当另一个函数调用pickle.load时,load_data()行会出错。但是,a)cPicklecpickle不再出现在项目中的任何源文件中(全局搜索)和b)如果我在load_data()中运行行,则不会发生错误单独在Python shell中(但是,我确实得到另一个数据格式错误)。 pickle是否正在调用cPickle,如果是,请如何停止?

外壳: Python 3.5.0 | Anaconda 2.4.0(x86_64)| (默认,2015年10月20日,14:39:26) [dclwin上的[GCC 4.2.1(Apple Inc. build 5577)]

IDE:IntelliJ 15.0.1,Python 3.5.0,anaconda

不清楚如何继续。任何帮助赞赏。感谢。

5 个答案:

答案 0 :(得分:7)

实际上,如果你有来自python2.x的腌制对象,通常可以python3.x阅读。此外,如果您有来自python3.x的腌制对象,则python2.x通常可以读取它们,但前提是它们被protocol设置为2或更低时转储。

Python 2.7.10 (default, Sep  2 2015, 17:36:25) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> x = [1,2,3,4,5]
>>> import math
>>> y = math.sin
>>>     
>>> import pickle 
>>> f = open('foo.pik', 'w') 
>>> pickle.dump(x, f)
>>> pickle.dump(y, f)
>>> f.close()
>>> 
dude@hilbert>$ python3.5
Python 3.5.0 (default, Sep 15 2015, 23:57:10) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pickle
>>> with open('foo.pik', 'rb') as f:
...   x = pickle.load(f)
...   y = pickle.load(f)
... 
>>> x
[1, 2, 3, 4, 5]
>>> y
<built-in function sin>

另外,如果您正在寻找cPickle,那么它现在是_pickle,而不是pickle

>>> import _pickle
>>> _pickle
<module '_pickle' from '/opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload/_pickle.cpython-35m-darwin.so'>
>>> 

您还询问了如何阻止pickle使用内置(C ++)版本。如果您想使用类对象,可以使用_dump_load_Pickler类来执行此操作。困惑?旧cPickle现在为_pickle,但dumploaddumpsloads都指向_pickle ... _dump_load_dumps_loads指向纯python版本。例如:

>>> import pickle
>>> # _dumps is a python function
>>> pickle._dumps
<function _dumps at 0x109c836a8>
>>> # dumps is a built-in (C++)
>>> pickle.dumps
<built-in function dumps>
>>> # the Pickler points to _pickle (C++)
>>> pickle.Pickler 
<class '_pickle.Pickler'>
>>> # the _Pickler points to pickle (pure python)
>>> pickle._Pickler
<class 'pickle._Pickler'>
>>> 

因此,如果您不想使用内置版本,则可以使用pickle._loads等。

答案 1 :(得分:4)

看起来你试图加载的pickle数据是由在Python 2.7上运行的程序版本生成的。数据包含对cPickle的引用。

问题在于,作为序列化格式的Pickle假定您的标准库(在较小程度上您的代码)不会更改序列化和反序列化之间的布局。它在Python 2和3之间做了很多 - 当发生这种情况时,Pickle没有迁移的途径。

您是否有权访问生成mnist.pkl.gz的程序?如果是这样,将其移植到Python 3并重新运行它以重新生成该文件的Python 3兼容版本。

如果没有,你将不得不编写一个加载该文件的Python 2程序并将其导出为可以从Python 3加载的格式(取决于数据的形状,JSON和CSV是流行的选择),然后编写一个加载该格式的Python 3程序,然后将其转储为Python 3 pickle。然后,您可以从原始程序加载该Pickle文件。

当然,你应该真正做的是停止在你能够从Python 3加载导出格式的位置 - 并使用上述格式作为实际的长期存储格式。

使用Pickle进行除可信程序之间的短期序列化之外的任何事情(加载Pickle相当于在Python VM中运行任意代码)是你应该主动避免的事情,其中​​包括:确切的情况你发现自己。

答案 2 :(得分:3)

在Anaconda Python3.5中: 一个人可以访问cPickle

import _pickle as cPickle

Mike McKerns

答案 3 :(得分:0)

这绕过了技术问题,但可能有一个名为mnist_py3k.pkl.gz的文件的py3版本。如果是这样,请尝试打开该文件。

答案 4 :(得分:0)

在github中有一个代码可以做到:https://gist.github.com/rebeccabilbro/2c7bb4d1acfbcdcf9156e7b9b7577cba

我已经尝试过了,并且奏效了。您只需要指定编码,在这种情况下为“ latin1”:

pickle.load(open('mnist.pkl','rb'), encoding = 'latin1')