具有字符串内容的pickle中io的不同行为

时间:2014-10-09 13:30:39

标签: python-2.7 unicode io pickle python-unicode

使用pickle数据时,我遇到了io.open__builtin__.open的不同行为。请考虑以下简单示例:

import pickle

payload = 'foo'
fn = 'test.pickle'

pickle.dump(payload, open(fn, 'w'))
a = pickle.load(open(fn, 'r'))

这可以按预期工作。但是在这里运行此代码:

import pickle
import io

payload = 'foo'
fn = 'test.pickle'

pickle.dump(payload, io.open(fn, 'w'))
a = pickle.load(io.open(fn, 'r'))

给出以下Traceback:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "D:\WinPython-32bit-2.7.8.1\python-2.7.8\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 580, in runfile
    execfile(filename, namespace)
  File "D:/**.py", line 15, in <module>
    pickle.dump(payload, io.open(fn, 'w'))
  File "D:\WinPython-32bit-2.7.8.1\python-2.7.8\lib\pickle.py", line 1370, in dump
    Pickler(file, protocol).dump(obj)
  File "D:\WinPython-32bit-2.7.8.1\python-2.7.8\lib\pickle.py", line 224, in dump
    self.save(obj)
  File "D:\WinPython-32bit-2.7.8.1\python-2.7.8\lib\pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "D:\WinPython-32bit-2.7.8.1\python-2.7.8\lib\pickle.py", line 488, in save_string
    self.write(STRING + repr(obj) + '\n')
TypeError: must be unicode, not str

由于我希望与未来兼容,我怎样才能避免这种不端行为呢?或者,我还有什么不对吗?

在使用string类型的键转储字典时,我偶然发现了这一点。

我的python版本是: '2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)]'

1 个答案:

答案 0 :(得分:2)

差别不大,因为io.open() 显式在使用文本模式时处理Unicode字符串。文档非常清楚:

  

注意:由于此模块主要是为Python 3.x设计的,因此您必须注意本文档中“bytes”的所有用法均指str类型(其中bytes是别名),“text”的所有用法均指unicode类型。此外,这两种类型在io API中不可互换。

  

Python区分以二进制和文本模式打开的文件,即使底层操作系统没有。以二进制模式打开的文件(包括模式参数中的'b')将内容作为bytes对象返回,而不进行任何解码。在文本模式下(默认情况下,或模式参数中包含't'时),文件内容将作为unicode字符串返回,字节已被首先解码使用依赖于平台的编码或使用指定的编码(如果给定)。

您需要以二进制模式打开文件。事实上它没有内置的open(),实际上比智慧运气更多;如果您的泡菜包含\n和/或\r字节的数据,则泡菜加载可能会失败。 Python 2的默认pickle碰巧是一个文本协议,但输出应该仍被视为二进制。

在所有情况下,在编写pickle数据时,请使用二进制模式:

pickle.dump(payload, open(fn, 'wb'))
a = pickle.load(open(fn, 'rb'))

pickle.dump(payload, io.open(fn, 'wb'))
a = pickle.load(io.open(fn, 'rb'))