Разница между открытым и codecs.open в Python
Есть два способа открыть текстовый файл в Python:
f = open(filename)
А также
import codecs
f = codecs.open(filename, encoding="utf-8")
Когда codecs.open
предпочтительнее open
?
6 ответов
Начиная с 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
Теперь о первоначальном вопросе: при чтении текста (включая "обычный текст", HTML, XML и JSON) в Python 2 вы всегда должны использовать io.open()
с явным кодированием, или open()
с явной кодировкой в Python 3. Это означает, что вы получаете правильно декодированный Unicode или сразу получаете ошибку, что значительно упрощает отладку.
Чистый ASCII "простой текст" - это миф из далекого прошлого. Надлежащий английский текст использует фигурные кавычки, тире, маркеры, евро (знаки евро) и даже диарез (¨). Не будь наивным! (И давайте не будем забывать шаблон дизайна Фасада!)
Потому что чистый ASCII не является реальным вариантом, open()
без явной кодировки полезно только читать двоичные файлы.
Лично я всегда использую codecs.open
если нет четко определенной необходимости использования open
**. Причина в том, что было так много раз, когда я был укушен, когда в мои программы входил ввод utf-8. "О, я просто знаю, что это всегда будет ascii" - это предположение, которое часто нарушается.
Принятие 'utf-8' в качестве кодировки по умолчанию, по моему опыту, является более безопасным выбором по умолчанию, поскольку ASCII может рассматриваться как UTF-8, но обратное неверно. И в тех случаях, когда я действительно знаю, что вход ASCII, то я все еще знаю codecs.open
поскольку я твердо верю в "явное лучше, чем неявное".
** - в Python 2.x, как говорится в комментарии к вопросу в Python 3 open
заменяет codecs.open
В Python 2 есть строки Юникода и строки байтов. Если вы просто используете bytestrings, вы можете читать / писать в файл, открытый с 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. Легко быть укушенным этим.
Также 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)
Совет по строкам для ввода / вывода обычно "конвертирует в юникод как можно раньше, а обратно в байтовые строки как можно позже". С помощью codecs.open
позволяет сделать последнее очень легко.
Просто будьте осторожны с тем, что вы даете ему строки в юникоде, а не строки байтов, которые могут содержать символы не ASCII.
codecs.open
Полагаю, это всего лишь остаток от Python 2
дни, когда встроенный open имел гораздо более простой интерфейс и меньше возможностей. В 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.open
такой же как built-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
модуль.
Если вы хотите загрузить бинарный файл, используйте
f = open(filename, 'b')
,А при открытии текстового файла используйте
f = io.open(filename, encoding='utf-8')
,
В питоне 3 однако open(filename, encoding='utf-8')
делает то же самое и может быть использован вместо.
Замечания:
codecs.open
в настоящее время устарела и замененаio.open
после его введения в Python 2.6. Для получения дополнительной информации о кодеках и Unicode в Python см. Unicode HOWTO.
Когда вы работаете с текстовыми файлами и хотите прозрачное кодирование и декодирование в объекты Unicode.
Я был в ситуации, чтобы открыть файл.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:
Без особых проблем я могу прочитать весь файл, есть предложения?