繁体   English   中英

Python pickle 调用 cPickle?

[英]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) cPicklecpickle不再出现在项目的任何源文件中(全局搜索)和 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 ,但是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之类的。

看起来您尝试加载的腌制数据是由在 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 中运行任意代码)是您应该积极避免的事情,尤其是因为您所处的确切情况。

在 Anaconda Python3.5 中:可以访问 cPickle 作为

import _pickle as cPickle

归功于Mike McKerns

这绕过了技术问题,但该文件可能有一个名为 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM