Python中open和codecs.open之间的区别


93

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

f = open(filename)

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

什么时候codecs.openopen


44
请注意codecs.open(),由于open()获得了encoding参数,在3.x 中已过时。
伊格纳西奥·巴斯克斯

还有第三种方式(至少在Python 2.x中如此):`f = file(filename)'
Adam Parkin 2012年

1
@ IgnacioVazquez-Abrams是否有任何codecs.open()过时的链接?我认为在python3文档中不会这样:docs.python.org/3.7/library/codecs.html
varela

1
@varela:您提到的Python文档页面说:“推荐使用内置的open()和关联的io模块来处理编码的文本文件”
Luciano Ramalho,

Answers:


82

从Python 2.6开始,一种好的做法是使用io.open(),它也需要一个encoding参数,例如now过时codecs.open()。在Python 3中,io.openopen()内置别名。因此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()没有显式编码仅对读取二进制文件有用。


5
@ForeverWintr答案很明显:io.open()用于文本,open()仅用于二进制。这意味着根本codecs.open()不是首选。
Bdoserror

2
@Bdoserror,很显然那里有一个答案,但这不是对所问问题的答案。该问题是关于之间的差opencodecs.open,并且特别是当后者是优选前者。没有提到的codecs.open答案就不能回答这个问题。
ForeverWintr

3
@ForeverWintr如果OP提出了错误的问题(即使用codecs.open()正确的假设),则没有关于何时使用它的“正确”答案。答案是io.open()改用。就像我问“何时使用扳手将钉子钉入墙壁?”。正确的答案是“用锤子”。
Bdoserror

20

就个人而言,除非明确确定需要使用**,否则我总是使用。原因是有很多次我被utf-8输入偷偷摸摸地刺入我的程序。“哦,我只知道它永远是ascii”,这是一个经常被打破的假设。codecs.openopen

在我的经验中,假设将'utf-8'用作默认编码是一种比较安全的默认选择,因为ASCII可以视为UTF-8,但事实并非如此。在那些我确实确实知道输入是ASCII的情况下,我仍然会codecs.open坚决相信“显式胜于隐式”

**-在Python 2.x中,因为在Python 3中对问题状态的注释已open替换codecs.open


我真正不明白的是,为什么open有时可以很好地处理unicode集的UTF-8编码非拉丁字符,有时却无法正常工作……
cedbeu 2013年

这对我来说很有意义。io.open我没有在python 2.7.5中看到的编码参数
-radtek

1
@radtek,您说对了,这是正确的,您是对的;但是(至少在2.7.12中)io.open接受encodingnewline参数并像Python 3一样解释它们。不同于codecs.open,如果您尝试向其中写入(),则使用python 打开的文件甚至会在python 2.7中io.open引发。用打开的文件将尝试隐式转换为,通常会导致s 混乱。TypeError: write() argument 1 must be unicode, not strstrbytescodecs.openunicodeUnicodeDecodeError
jochietoch

9

在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字符串不合适。
Mandible79

7

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


15
我猜所有的文本文件都有某种编码,以某种方式(:
cedbeu 2013年

5

codecs.open我想,这只是Python 2内置开放式接口界面更简单,功能更少的时代的残余。在Python 2中,内置open函数不带编码参数,因此,如果要使用二进制模式或默认编码以外的其他方式,则应使用codecs.open。

在中Python 2.6,io模块有助于使事情更简单。根据官方文件

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 <2.6),最好使用io.open。也Python 3.x io.openbuilt-in open

注意:

codecs.open和之间也存在语法差异io.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始终以二进制模式处理文件。
wombatonfire

4
  • 要加载二进制文件时,请使用 f = io.open(filename, 'b')

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

然而,在python 3中,open它的功能与相同io.open,可以代替使用。

注意: codecs.open计划在python 2.6中引入后被弃用并替换为。仅当代码需要与早期python版本兼容时才使用它。有关python中的编解码器和unicode的更多信息,请参见Unicode HOWTOio.open


1.为什么我不能使用io.open或以二进制模式打开文件codecs.open?2. codecs.open尚未弃用,请阅读链接到的页面上的讨论。
wombatonfire

好点!1.您可以使用任何一种,但是除非您使用的是python 2.5或更早版本,否则我还是会再次建议您不要使用codecs.open。2.我更新了答案,以反映弃用不是立即发生,而是将来发生。
wihlke '19

3

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


0

我当时处于打开.asm文件并处理该文件的情况。

#https://docs.python.org/3/library/codecs.html#codecs.ignore_errors
#https://docs.python.org/3/library/codecs.html#codecs.Codec.encode
with codecs.open(file, encoding='cp1252', errors ='replace') as file:

没有太多麻烦,我就能读取整个文件,有什么建议吗?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.