【问题标题】:Python pickle calls cPickle?Python pickle 调用 cPickle?
【发布时间】:2015-11-17 00:28:48
【问题描述】:

我是 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)] 在 darwin 上

IDE:IntelliJ 15.0.1、Python 3.5.0、anaconda

不清楚如何进行。任何帮助表示赞赏。谢谢。

【问题讨论】:

  • 检查.pyc 文件并删除它们。它们可能已经过时了。

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


【解决方案1】:

其实如果你有来自python2.x的pickle对象,那么一般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 987654346@指向纯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之类的。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 谢谢马克斯。我无权访问生成腌制数据文件的代码,但我可以尝试在 Python 2.7 下运行来读取它们。
    • 我正在使用 Python 3.6.6,并尝试了所有方法:将 pickle 导入为 cPickle,导入 pickle,将 _pickle 导入为 cPickle,但仍然出现错误“ModuleNotFoundError: No module named 'cPickle'”
    • @pari 这与这个问题无关,但在 Python 3 中没有 cPickle 了。只需使用import pickle(或者更好,不要使用 Pickle,它仍然是一种缓慢、不安全、糟糕的序列化格式——改用 JSON)。
    【解决方案3】:

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

    import _pickle as cPickle
    

    感谢Mike McKerns

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

        我试过了,效果很好。你只需要指定编码,在这种情况下它是'latin1':

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

        【讨论】:

          猜你喜欢
          • 2021-03-04
          • 2016-09-03
          • 1970-01-01
          • 2016-04-28
          • 1970-01-01
          • 2011-01-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多