[英]Python pickle calls cPickle?
我是 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)
当另一个函数调用load_data()
时, pickle.load
行中发生错误。 但是,a) cPickle
或cpickle
不再出现在项目的任何源文件中(全局搜索)和 b)如果我在 Python shell 中单独运行load_data()
的行,则不会发生错误(但是,我会得到另一个数据格式错误)。 pickle
是否正在调用cPickle
,如果是,我该如何阻止它?
外壳:Python 3.5.0 |Anaconda 2.4.0 (x86_64)| (默认,2015 年 10 月 20 日,14:39:26)[GCC 4.2.1 (Apple Inc. build 5577)] 在达尔文上
IDE:IntelliJ 15.0.1、Python 3.5.0、anaconda
不清楚如何进行。 任何帮助表示赞赏。 谢谢。
实际上,如果您从python2.x
腌制了对象,那么通常可以通过python3.x
读取。 此外,如果您从python3.x
腌制了对象,它们通常可以被python2.x
读取,但python3.x
是它们使用设置为2
或更少的protocol
进行转储。
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
之类的。
看起来您尝试加载的腌制数据是由在 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 中运行任意代码)是您应该积极避免的事情,尤其是因为您所处的确切情况。
这绕过了技术问题,但该文件可能有一个名为 mnist_py3k.pkl.gz 的 py3 版本。如果是这样,请尝试打开该文件。
github中有一段代码可以做到: https : //gist.github.com/rebeccabilbro/2c7bb4d1acfbcdcf9156e7b9b7577cba
我已经试过了,它奏效了。 您只需要指定编码,在本例中为“latin1”:
pickle.load(open('mnist.pkl','rb'), encoding = 'latin1')
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.