Python中open和codecs.open的区别

128 投票
7 回答
98657 浏览
提问于 2025-04-16 13:22

在Python中,有两种方法可以打开一个文本文件:

f = open(filename)

还有一种方法是:

import codecs
f = codecs.open(filename, encoding="utf-8")

那么,什么时候使用 codecs.openopen 更好呢?

7 个回答

12

在Python 2中,有两种字符串类型:unicode字符串和字节字符串。如果你只使用字节字符串,那么用open()打开文件时,读写操作都没有问题。毕竟,字符串就是字节。

问题出现在你有一个unicode字符串时,比如你执行以下操作:

>>> example = u'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

在这种情况下,你显然需要将你的unicode字符串明确地编码为utf-8,或者使用codecs.open来自动处理这个问题。

如果你只使用字节字符串,那就没有任何问题:

>>> example = 'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
>>>

事情变得复杂的是,当你用+运算符把一个unicode字符串和一个字节字符串连接在一起时,结果会是一个unicode字符串。这一点很容易让人出错。

另外,codecs.open不喜欢传入包含非ASCII字符的字节字符串:

codecs.open('test', 'w', encoding='utf-8').write('Μου αρέσει')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/codecs.py", line 691, in write
    return self.writer.write(data)
  File "/usr/lib/python2.7/codecs.py", line 351, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 0: ordinal not in range(128)

关于字符串的输入/输出,通常的建议是“尽早转换为unicode,尽晚转换回字节字符串”。使用codecs.open可以很方便地做到这一点。

只要小心确保你传入的是unicode字符串,而不是可能包含非ASCII字符的字节字符串。

23

我个人总是使用 codecs.open,除非有明确的理由需要用 open。原因是我曾经遇到过很多次,程序里意外地出现了 utf-8 的输入。“哦,我就知道它肯定是 ascii 格式的”这种想法经常会被打破。

在我看来,把 'utf-8' 当作默认编码通常是更安全的选择,因为 ASCII 可以被当作 UTF-8 来处理,但反过来就不行。而在那些我确实知道输入是 ASCII 的情况下,我还是会用 codecs.open,因为我坚信 “显式比隐式好”

** - 在 Python 2.x 中,正如问题评论所说,在 Python 3 中 open 替代了 codecs.open

95

自从Python 2.6开始,使用io.open()是个好习惯,它也可以接受一个encoding参数,类似于现在已经不再使用的codecs.open()。在Python 3中,io.open其实就是内置的open()的别名。所以io.open()在Python 2.6及以后的版本,包括Python 3.4中都可以使用。详细信息可以查看文档:http://docs.python.org/3.4/library/io.html

现在,关于最初的问题:在Python 2中读取文本(包括“纯文本”、HTML、XML和JSON)时,你总是应该使用io.open()并指定编码,或者在Python 3中使用open()并指定编码。这样做的好处是你可以正确解码Unicode,或者一开始就能看到错误,这样调试起来就简单多了。

纯ASCII的“纯文本”其实是个遥远过去的神话。正确的英文文本会使用弯引号、长破折号、项目符号、€(欧元符号)甚至变音符号(¨)。别太天真了!(还有别忘了外观设计模式!)

因为纯ASCII并不是一个真正的选择,所以open()如果不指定编码仅仅适合用来读取二进制文件。

撰写回答