【问题标题】:Difference between open and codecs.open in PythonPython中open和codecs.open的区别
【发布时间】:2011-07-12 04:00:02
【问题描述】:

在 Python 中打开文本文件有两种方式:

f = open(filename)

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

codecs.open 何时优于 open

【问题讨论】:

  • 请注意,codecs.open() 在 3.x 中已过时,因为 open() 获得了 encoding 参数。
  • 还有第三种方式(至少在 Python 2.x 中):`f = file(filename)'
  • @IgnacioVazquez-Abrams 是否有任何链接表明codecs.open() 已过时?我不认为这在 python3 文档中:docs.python.org/3.7/library/codecs.html
  • @varela:你提到的 Python 文档页面说:“内置的 open() 和相关的 io 模块是处理编码文本文件的推荐方法”

标签: python unicode codec


【解决方案1】:

从 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()使用显式编码,或 open() 在 Python 3 中使用显式编码。这样做意味着您可以正确解码 Unicode,或者立即得到错误,从而更容易调试。

纯ASCII“纯文本”是遥远过去的神话。正确的英文文本使用花引号、破折号、项目符号、€(欧元符号)甚至分音符 (¨)。不要天真! (我们不要忘记外观设计模式!)

因为纯 ASCII 不是一个真正的选择,所以没有显式编码的open()对读取二进制文件有用。

【讨论】:

  • @ForeverWintr 答案很明确:将io.open() 用于文本,open() 仅用于二进制。这意味着codecs.open() 根本不是首选。
  • @Bdoserror,那里有 an 答案,很明显,但这不是对所提问题的答案。问题是关于opencodecs.open 之间的区别,特别是当后者比前者更可取时。没有提及codecs.open 的答案无法回答这个问题。
  • @ForeverWintr 如果 OP 提出了 wrong 问题(即假设 codecs.open() 使用正确),则没有关于何时使用的“正确”答案用它。答案是改用io.open()。就像我问“我什么时候应该用扳手把钉子钉进墙上?”。正确答案是“使用锤子”。
【解决方案2】:

就个人而言,我总是使用codecs.open,除非明确确定需要使用open**。原因是有很多次我被 utf-8 输入潜入我的程序中。 “哦,我只知道它总是 ascii”往往是一个经常被打破的假设。

根据我的经验,假设 'utf-8' 作为默认编码往往是一个更安全的默认选择,因为 ASCII 可以被视为 UTF-8,但反之则不然。在那些情况下,当我真正知道输入是 ASCII 时,我仍然会使用 codecs.open,因为我坚信 "explicit is better than implicit"

** - 在 Python 2.x 中,作为 Python 3 中问题状态的评论 open 替换 codecs.open

【讨论】:

  • 我真的不明白为什么open 有时可以很好地处理 UTF-8 编码的 unicode 集的非拉丁字符,有时它会惨遭失败......
  • 这对我来说很有意义。 io.open 没有从我在 python 2.7.5 中看到的编码参数
  • @radtek,你说得对,这是无证的;但是(至少在 2.7.12 中)io.open 接受 encodingnewline 参数并像 Python 3 一样解释它们。与codecs.open 不同,如果您尝试向其写入str (bytes),即使在Python 2.7 中,使用io.open 打开的文件也会引发TypeError: write() argument 1 must be unicode, not str。使用codecs.open 打开的文件将尝试隐式转换为unicode,这通常会导致混淆UnicodeDecodeErrors。
【解决方案3】:

在 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)

因此,很明显,您要么在 utf-8 中显式编码您的 unicode 字符串,要么使用 codecs.open 透明地为您执行此操作。

如果你只使用过字节串,那么没问题:

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

它比这更复杂,因为当您使用 + 运算符连接 unicode 和 bytestring 字符串时,您会得到一个 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 字符的字节字符串。

【讨论】:

  • 你能解释一下你的第二个例子吗?它似乎与您的第一个示例相同,那么为什么结果会有所不同?
  • 请注意第一个示例中u'' 的使用。这意味着我创建了一个 unicode 字符串,而不是一个字节串。这是两个示例之间的区别。在第二个示例中,我正在创建一个字节串并将其中一个写入文件就可以了。如果您使用 ASCII 以外的字符,则 unicode 字符串不适用。
【解决方案4】:

当您需要打开具有特定编码的文件时,您将使用codecs 模块。

【讨论】:

  • 我猜所有的文本文件都有某种编码,不知何故(:
【解决方案5】:

codecs.open,我想,只是 Python 2 时代的残余,当时内置的 open 具有更简单的界面和更少的功能。在 Python 2 中,内置的 open 不带编码参数,所以如果你想使用二进制模式或默认编码以外的东西,应该使用 codecs.open。

Python 2.6 中,io 模块提供了帮助,使事情变得更简单。 据官方documentation

New in version 2.6.

The io module provides the Python interfaces to stream handling.
Under Python 2.x, this is proposed as an alternative to the
built-in file object, but in Python 3.x it is the default
interface to access files and streams.

话虽如此,在当前情况下,我能想到的唯一用途 codecs.open 是为了向后兼容。在所有其他情况下(除非您使用 Python io.open。同样在Python 3.x io.openbuilt-in open 相同

注意:

codecs.openio.open 在语法上也有区别。

codecs.open:

open(filename, mode='rb', encoding=None, errors='strict', buffering=1)

io.open:

open(file, mode='r', buffering=-1, encoding=None,
     errors=None, newline=None, closefd=True, opener=None)

【讨论】:

  • codecs.openio.open 不仅语法不同,它们返回的对象类型也不同。此外,codecs.open 始终适用于二进制模式的文件。
【解决方案6】:
  • 如果要加载二进制文件,请使用 f = io.open(filename, 'b').

  • 要打开文本文件,请始终使用带有显式编码的f = io.open(filename, encoding='utf-8')

python 3 中,openio.open 做同样的事情,可以代替使用。

注意:codecs.openpython 2.6中引入后,计划变为deprecated并替换为io.open。如果代码需要与早期的 python 版本兼容,我只会使用它。有关 python 中编解码器和 unicode 的更多信息,请参阅Unicode HOWTO

【讨论】:

  • 1.为什么我不能用io.opencodecs.open 以二进制模式打开文件? 2. codecs.open 尚未弃用,请阅读您链接到的页面上的讨论。
  • 好点! 1. 你可以使用其中任何一个,但我会再次建议不要使用 codecs.open,除非你使用的是 python 2.5 或更早版本。 2. 我更新了我的答案以反映弃用不是立即发生,而是在未来发生。
【解决方案7】:

当您处理文本文件并希望将透明编码和解码为 Unicode 对象时。

【讨论】:

    猜你喜欢
    • 2013-04-14
    • 2016-02-26
    • 1970-01-01
    • 1970-01-01
    • 2021-08-07
    • 2017-05-27
    • 2012-04-15
    • 1970-01-01
    相关资源
    最近更新 更多