Существует два способа открыть текстовый файл в Python:
f = open(filename)
и
import codecs
f = codecs.open(filename, encoding="utf-8")
Когда codecs.open
предпочтительнее open
?
Существует два способа открыть текстовый файл в Python:
f = open(filename)
и
import codecs
f = codecs.open(filename, encoding="utf-8")
Когда codecs.open
предпочтительнее open
?
С 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 "простой текст" - это миф из далекого прошлого. Правильный английский текст использует фигурные кавычки, em-тире, маркеры, евро (знаки евро) и даже диарезис (¨). Не будь наивным! (И не забывайте о шаблоне дизайна фасада!)
Поскольку чистый 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 есть строки unicode и bytestrings. Если вы просто используете bytestrings, вы можете читать/записывать в файл, открытый с помощью open()
, просто отлично. В конце концов, строки - это просто байты.
Проблема возникает, когда, скажем, у вас есть строка в Юникоде, и вы делаете следующее:
>>> 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
, чтобы сделать это для вас прозрачно.
Если вы только когда-либо используете bytestrings, тогда никаких проблем:
>>> example = 'Μου αρέσει Ελληνικά'
>>> open('sample.txt', 'w').write(example)
>>>
Он становится более привлекательным, чем это, потому что когда вы объединяете строку unicode и bytestring с помощью оператора +
, вы получаете строку юникода. Легко укусить его.
Также 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
позволяет сделать последнее очень легко.
Просто будьте осторожны, вы указываете строки unicode, а не теги, которые могут иметь символы, отличные от ASCII.
Когда вам нужно открыть файл с определенной кодировкой, вы должны использовать модуль codecs
.
codecs.open
, codecs.open
- это всего лишь остаток от Python 2
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.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)
Когда вы работаете с текстовыми файлами и хотите прозрачную кодировку и декодирование в объекты Unicode.
Если вы хотите загрузить двоичный файл, используйте f = io.open(filename, 'b')
.
Для открытия текстового файла всегда используйте f = io.open(filename, encoding='utf-8')
с явной кодировкой.
Однако в python 3 open
делает то же самое, что и io.open
и может использоваться вместо него.
Примечание:
codecs.open
планируется стать устаревшим и замененio.open
после его введения в Python 2.6. Я бы использовал его, только если код должен быть совместим с более ранними версиями Python. Для получения дополнительной информации о кодеках и Unicode в Python см. Unicode HOWTO.