我是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)cPickle
或cpickle
不再出现在项目中的任何源文件中(全局搜索)和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
不清楚如何继续。任何帮助赞赏。感谢。
答案 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
,但dump
,load
,dumps
和loads
都指向_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)
答案 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')